#ifdef CHANGED

//======== CSCI402 Project 1, Part 2 ========

#include "movietheater.h"

//======== Global Data ========

bool PRINT_DEBUG_MESSAGES = true;
bool PRINT_OUTPUT_MESSAGES = false;
bool PRINT_TEST_CASE_MESSAGES = false;
bool ENABLE_BREAKS = false;

//-------- Constants --------

//monetary constants
int TICKET_PRICE = 12;
int POPCORN_PRICE = 5;
int SODA_PRICE = 4;

//clerk amounts
int NUM_TICKET_CLERKS = 5;
int NUM_CONCESSION_CLERKS = 5;
int NUM_TICKET_TAKERS = 3;

//customer amounts
int NUM_CUSTOMERS = 40;
int NUM_GROUPS = 25;
int MAX_GROUP_SIZE = 5;

//customer probability constants
int CUSTOMER_WANT_POPCORN_PROBABILITY = 75;
int CUSTOMER_WANT_SODA_PROBABILITY = 75;
int CUSTOMER_WANT_BATHROOM_PROBABILITY = 25;

//screening room properties
int SCREENING_ROOM_ROWS = 5;
int SCREENING_ROOM_COLS = 5;
int SCREENING_ROOM_CAPACITY = SCREENING_ROOM_ROWS * SCREENING_ROOM_COLS;

//manager probability constants
const int MANAGER_DELAY_ACCEPTING = 1; // nonzero: bigger numbers and the manager will roll less often to start movie process
const int MANAGER_ROLL_ACCEPT = 50; // % chance to start movie process when deciding to roll for it
const int MANAGER_YIELD_ACCEPTING = 15; //manager yields cpu this many times after activating ticket takers so he doesnt randomly set state to CUSTOMER_CUTOFF too soon.
const int MANAGER_DELAY_CUTOFF = 1; //nonzero: bigger numbers and the manager will stop the taking of tickets so the movie will start less often
const int MANAGER_DELAY_PROFITS = 5; //nonzero: bigger numbers and the manager will check profits less often
const int MANAGER_DELAY_BREAK = 1;// nonzero: bigger numbers and the manager will roll to put people on break less often
const int MANAGER_ROLL_ONBREAK = 20;//% chance to put someone on break when rolling to decide to do it

const int MANAGER_LONGLINE = 5; //lines longer than this end breaks
const int MANAGER_SHORTLINE = 3; //lines shorter than this start breaks

//movie technician
//const int MOVIETECH_YIELD = 30;

//-------- Enums --------

//customer initialization modes
const int CONSTANT_NUMBER_OF_CUSTOMERS = 0, CONSTANT_NUMBER_OF_GROUPS = 1;
int CUSTOMER_INIT_MODE = CONSTANT_NUMBER_OF_CUSTOMERS;

//clerk states
const int CLERK_ON_BREAK = -1, CLERK_AVAILABLE = 0, CLERK_BUSY = 1;

//movie process states
const int ROOM_EMPTY = 0, ACCEPTING_TICKETS = 1, CUSTOMER_CUTOFF = 2, IN_PROGRESS = 3, ROOM_EMPTYING = 4;
int MOVIE_STATE = ROOM_EMPTY;

//-------- General movie theater data --------

int numCustomersInTheater;
Lock* numCustomersInTheaterLock;
int numGroupsInTheater;
Lock* numGroupsInTheaterLock;

int* totalTicketsSold;
int* totalPopcornSold;
int* totalSodaSold;

int ticketCountBox;
Lock* ticketCountBoxLock;

Lock* movieStateLock;
int movieNumber;

//-------- Special/Testing data --------

Condition* overrideExitCondition;
Lock* overrideExitLock;

//-------- Screening room data --------

int** screeningRoomSeat;
Lock* screeningRoomLock;
Lock* movieInProgressLock;
Condition* movieInProgressCondition;

//-------- Data, Locks, and Conditions controlling the Customers --------

Lock* customerInitLock;
Condition* customerInitCondition;
Lock* customerStartLock;
Condition* customerStartCondition;

//-------- Data, Locks, and Conditions controlling the TicketClerks --------

int* tcLineLength;
Lock* tcLineManager;
Lock** tcInteractionLock;
Condition** tcLineCondition;
Condition** tcInteractionCondition;

int* tcState;
Lock** tcStateLock;
Condition** tcStateCondition;

int* numTicketsDesired;

//-------- Data, Locks, and Conditions controlling the ConcessionClerks --------

int* ccLineLength;
Lock* ccLineManager;
Lock** ccInteractionLock;
Condition** ccLineCondition;
Condition** ccInteractionCondition;

int* ccState;
Lock** ccStateLock;
Condition** ccStateCondition;

int* numPopcornDesired;
int* numSodaDesired;

//-------- Data, Locks, and Conditions controlling the TicketTakers --------

int* ttLineLength;
Lock* ttLineManager;
Lock** ttInteractionLock;
Condition** ttLineCondition;
Condition** ttInteractionCondition;
Condition** ttLobbyCondition;
Lock** ttLobbyLock;

Lock* ticketTakerFullLock;
bool* ticketTakerFull;
bool* ticketTakerSaidToProceed;
int* ttState;
Lock** ttStateLock;
Condition** ttStateCondition;

Lock* ttStopLock;
Condition* ttStopCondition;

bool* ttForcedToStop;

int* numTicketsGiven;

//-------- Data, Locks, and Conditions used by the Manager -------

Lock** beginTakingTicketsLock;
Condition** beginTakingTicketsCondition;
int tcsOnBreak;
int ccsOnBreak;
int ttsOnBreak;

Lock** tcBreakLock;
Lock** tcBreakStopLock;
Condition** tcBreakCondition;
Condition** tcBreakStopCondition;
Lock** ccBreakLock;
Lock** ccBreakStopLock;
Condition** ccBreakCondition;
Condition** ccBreakStopCondition;
Lock** ttBreakLock;
Lock** ttBreakStopLock;
Condition** ttBreakCondition;
Condition** ttBreakStopCondition;

//======== Function that returns the number of available seats in the theater ========
int getNumAvailableSeats()
{
	int total = 0;
	
	for(int r = 0; r < SCREENING_ROOM_ROWS; r++)
	{
		total += getNumFreeSeats(r);
	}
	
	return total;
}

//======== Function that returns the number of taken seats in the theater ========
int getNumTakenSeats()
{
	return SCREENING_ROOM_CAPACITY - getNumAvailableSeats();
}

//-------- Data, Locks, and Conditions used by the Manager -------

Lock* movieTechLock;
Condition* movieTechCondition;
Lock* profitLock;

//======== Function that returns the number of free seats in a screening room row ========
int getNumFreeSeats(int row)
{
	int freeSeats = 0;
	for(int col = 0; col < SCREENING_ROOM_COLS; col++)
	{
		if(screeningRoomSeat[row][col] < 0)
		{
			freeSeats++;
		}
	}
	return freeSeats;
}

//======== Function that returns the index of the biggest row ========
int getBiggestRow()
{
	int biggestRow = 0;
	int biggestRowSize = getNumFreeSeats(0);
	
	for(int r = 1; r < SCREENING_ROOM_ROWS; r++)
	{
		int freeSeats = getNumFreeSeats(r);
		
		if(freeSeats > biggestRowSize)
		{
			biggestRow = r;
			biggestRowSize = getNumFreeSeats(r);
		}
	}
	
	return biggestRow;
}

//======== Function that returns the index of the smallest row that fits a specified number of people ========
int getSmallestRowThatFits(int numPeopleToSeat)
{
	bool rowThatFitsExists = false;
	int smallestRowThatFits = -1;
	for(int r = 0; r < SCREENING_ROOM_ROWS; r++)
	{
		if(getNumFreeSeats(r) >= numPeopleToSeat)
		{
			smallestRowThatFits = r;
			rowThatFitsExists = true;
			break;
		}
	}
	
	if(smallestRowThatFits == -1)
	{
		return -1;
	}
	else
	{
		int smallestRowThatFitsSize = getNumFreeSeats(smallestRowThatFits);
		for(int r = 0; r < SCREENING_ROOM_ROWS; r++)
		{
			int numFreeSeats = getNumFreeSeats(r);
			if(numFreeSeats >= numPeopleToSeat && numFreeSeats < smallestRowThatFitsSize)
			{
				smallestRowThatFits = r;
				smallestRowThatFitsSize = getNumFreeSeats(r);
			}
		}
		
		return smallestRowThatFits;
	}
}

//======== Sets up the movie theater ========

void setupMovieTheater(int numTicketClerks, int numConcessionClerks, int numTicketTakers,
	int numCustomers, int numGroups, int maxGroupSize, int customerInitMode,
	bool printTestCaseMessages, bool enableBreaks)
{
	NUM_TICKET_CLERKS = numTicketClerks;
	NUM_CONCESSION_CLERKS = numConcessionClerks;
	NUM_TICKET_TAKERS = numTicketTakers;
	NUM_CUSTOMERS = numCustomers;
	NUM_GROUPS = numGroups;
	MAX_GROUP_SIZE = maxGroupSize;
	CUSTOMER_INIT_MODE = customerInitMode;
	
	PRINT_TEST_CASE_MESSAGES = printTestCaseMessages;
	
	ENABLE_BREAKS = enableBreaks;
	
	setupMovieTheater();
}

void setupMovieTheater()
{
	if(PRINT_DEBUG_MESSAGES) printf("Setting up movie theater...\n");
	
	//-------- Global data --------
	
	numCustomersInTheater = 0;
	numCustomersInTheaterLock = new Lock("numCustomersInTheaterLock");
	numGroupsInTheater = 0;
	numGroupsInTheaterLock = new Lock("numGroupsInTheaterLock");
	
	totalTicketsSold = new int[NUM_TICKET_CLERKS];
	totalPopcornSold = new int[NUM_CONCESSION_CLERKS];
	totalSodaSold = new int[NUM_CONCESSION_CLERKS];

	ticketCountBox = 0;
	ticketCountBoxLock = new Lock("ticketCountBoxLock");
	
	movieStateLock = new Lock("movieStateLock");
	movieNumber = 0;
	
	//-------- Special/Testing data --------
	
	overrideExitCondition = new Condition("overrideExitCondition");
	overrideExitLock = new Lock("overrideExitLock");
	
	//-------- Screening room data --------
	
	screeningRoomSeat = new int*[SCREENING_ROOM_ROWS];
	for(int r = 0; r < SCREENING_ROOM_ROWS; r++)
	{
		screeningRoomSeat[r] = new int[SCREENING_ROOM_COLS];
		for(int c = 0; c < SCREENING_ROOM_COLS; c++)
		{
			screeningRoomSeat[r][c] = -1;
		}
	}
	
	screeningRoomLock = new Lock("screeningRoomLock");
	movieInProgressLock = new Lock("movieInProgressLock");
	movieInProgressCondition = new Condition("movieInProgessCondition");
	
	//-------- Customer data --------
	
	customerInitLock = new Lock("customerInitLock");
	customerInitCondition = new Condition("customerInitCondition");
	customerStartLock = new Lock("customerStart");
	customerStartCondition = new Condition("customerStartCondition");
	
	//-------- TicketClerk data --------
	
	tcLineLength = new int[NUM_TICKET_CLERKS];
	tcLineManager = new Lock("tcLineManager");
	tcInteractionLock = new Lock*[NUM_TICKET_CLERKS]();
	tcLineCondition = new Condition*[NUM_TICKET_CLERKS]();
	tcInteractionCondition = new Condition*[NUM_TICKET_CLERKS]();
	
	tcState = new int[NUM_TICKET_CLERKS];
	tcStateLock = new Lock*[NUM_TICKET_CLERKS]();
	tcStateCondition = new Condition*[NUM_TICKET_CLERKS]();
	
	numTicketsDesired = new int[NUM_TICKET_CLERKS];
	
	//-------- ConcessionClerk data --------
	
	ccLineLength = new int[NUM_CONCESSION_CLERKS];
	ccLineManager = new Lock("ccLineManager");
	ccInteractionLock = new Lock*[NUM_CONCESSION_CLERKS]();
	ccLineCondition = new Condition*[NUM_CONCESSION_CLERKS]();
	ccInteractionCondition = new Condition*[NUM_CONCESSION_CLERKS]();
	
	ccState = new int[NUM_CONCESSION_CLERKS];
	ccStateLock = new Lock*[NUM_CONCESSION_CLERKS]();
	ccStateCondition = new Condition*[NUM_CONCESSION_CLERKS]();
	
	numPopcornDesired = new int[NUM_CONCESSION_CLERKS];
	numSodaDesired = new int[NUM_CONCESSION_CLERKS];
	
	//-------- TicketTaker data --------
	
	ttLineLength = new int[NUM_TICKET_TAKERS];
	ttLineManager = new Lock("ttLineManager");
	ttInteractionLock = new Lock*[NUM_TICKET_TAKERS]();
	ttLineCondition = new Condition*[NUM_TICKET_TAKERS]();
	ttInteractionCondition = new Condition*[NUM_TICKET_TAKERS]();
	ttLobbyLock = new Lock*[NUM_TICKET_TAKERS + 1]();
	ttLobbyCondition = new Condition*[NUM_TICKET_TAKERS + 1]();
	
	ticketTakerFullLock = new Lock("ticketTakerFull");
	ticketTakerFull = new bool[NUM_TICKET_TAKERS];
	ticketTakerSaidToProceed = new bool[NUM_TICKET_TAKERS];
	ttState = new int[NUM_TICKET_TAKERS];
	ttStateLock = new Lock*[NUM_TICKET_TAKERS]();
	ttStateCondition = new Condition*[NUM_TICKET_TAKERS]();
	
	numTicketsGiven = new int[NUM_TICKET_TAKERS];
	
	ttForcedToStop = new bool[NUM_TICKET_TAKERS];
	
	ttStopCondition = new Condition("ttStopCondition");
	ttStopLock = new Lock("ttStopLock");
	
	//-------- Manager data --------
	
	beginTakingTicketsLock = new Lock*[NUM_TICKET_TAKERS]();
	beginTakingTicketsCondition = new Condition*[NUM_TICKET_TAKERS]();
	profitLock = new Lock("profitLock");
	tcsOnBreak = 0;
	ccsOnBreak = 0;
	ttsOnBreak = 0;
	
	tcBreakLock = new Lock*[NUM_TICKET_CLERKS]();
	tcBreakCondition = new Condition*[NUM_TICKET_CLERKS]();
	tcBreakStopLock = new Lock*[NUM_TICKET_CLERKS]();
	tcBreakStopCondition = new Condition*[NUM_TICKET_CLERKS]();
	
	ccBreakLock = new Lock*[NUM_CONCESSION_CLERKS]();
	ccBreakCondition = new Condition*[NUM_CONCESSION_CLERKS]();
	ccBreakStopLock = new Lock*[NUM_CONCESSION_CLERKS]();
	ccBreakStopCondition = new Condition*[NUM_CONCESSION_CLERKS]();
	
	ttBreakLock = new Lock*[NUM_TICKET_TAKERS]();
	ttBreakCondition = new Condition*[NUM_TICKET_TAKERS]();
	ttBreakStopLock = new Lock*[NUM_TICKET_TAKERS]();
	ttBreakStopCondition = new Condition*[NUM_TICKET_TAKERS]();
	
	
	
	//-------- MovieTech data --------
	
	movieTechLock = new Lock("movieTechLock");
	movieTechCondition = new Condition("movieTechCondition");
	
	//======== Array Initialization ========
	
	for(int i = 0; i < NUM_TICKET_CLERKS; i++)
	{
		//-------- TicketClerk data --------
		
		totalTicketsSold[i] = 0;
		
		tcLineLength[i] = 0;
		tcInteractionLock[i] = new Lock("tcInteractionLock");
		tcLineCondition[i] = new Condition("tcLineCondition");
		tcInteractionCondition[i] = new Condition("tcInteractionCondition");
		
		tcState[i] = CLERK_AVAILABLE;
		tcStateLock[i] = new Lock("tcStateLock");
		tcStateCondition[i] = new Condition("tcInteractionCondition");
		
		numTicketsDesired[i] = 0;
		
		tcBreakLock[i] = new Lock("tcBreakLock");
		tcBreakCondition[i] = new Condition("tcBreakCondition");
		tcBreakStopLock[i] = new Lock("tcBreakStopLock");
		tcBreakStopCondition[i] = new Condition("tcBreakStopCondition");
	}
	
	for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
	{
		//-------- ConcessionClerk data --------
		
		totalPopcornSold[i] = 0;
		totalSodaSold[i] = 0;
		
		ccLineLength[i] = 0;
		ccInteractionLock[i] = new Lock("ccInteractionLock");
		ccLineCondition[i] = new Condition("ccLineCondition");
		ccInteractionCondition[i] = new Condition("ccInteractionCondition");
		
		ccState[i] = CLERK_AVAILABLE;
		ccStateLock[i] = new Lock("ccStateLock");
		ccStateCondition[i] = new Condition("ccInteractionCondition");
		
		numPopcornDesired[i] = 0;
		numSodaDesired[i] = 0;
		
		ccBreakLock[i] = new Lock("ccBreakLock");
		ccBreakCondition[i] = new Condition("ccBreakCondition");
		ccBreakStopLock[i] = new Lock("ccBreakStopLock");
		ccBreakStopCondition[i] = new Condition("ccBreakStopCondition");
	}
	
	//-------- TicketTakers data --------
	
	for(int i = 0; i < NUM_TICKET_TAKERS; i++)
	{
		
		ttLineLength[i] = 0;
		ttInteractionLock[i] = new Lock("ttInteractionLock");
		ttLineCondition[i] = new Condition("ttLineCondition");
		ttInteractionCondition[i] = new Condition("ttInteractionCondition");
		
		ticketTakerFull[i] = true;
		ticketTakerSaidToProceed[i] = false;
		ttState[i] = CLERK_AVAILABLE;
		
		numTicketsGiven[i] = 0;
		
		ttForcedToStop[i] = false;
		
		ttStateLock[i] = new Lock("ttStateLock");
		ttStateCondition[i] = new Condition("ttInteractionCondition");
		
		ttBreakLock[i] = new Lock("ttBreakLock");
		ttBreakCondition[i] = new Condition("ttBreakCondition");
		ttBreakStopLock[i] = new Lock("ttBreakStopLock");
		ttBreakStopCondition[i] = new Condition("ttBreakStopCondition");
		
	}
	for(int i = 0; i < NUM_TICKET_TAKERS + 1; i++)
	{
		ttLobbyLock[i] = new Lock("ttLobbyLock");
		ttLobbyCondition[i] = new Condition("ttLobbyCondition");
	}
	
	//-------- Manager data --------
	
	for(int i = 0; i < NUM_TICKET_TAKERS; i++)
	{
		beginTakingTicketsLock[i] = new Lock("beginTakingTicketLock");
		beginTakingTicketsCondition[i] = new Condition("beginTakingTicketsCondition");
	}
	
	//======== Main Initialization Thread ========
	
	if(PRINT_DEBUG_MESSAGES) printf("Setup complete, starting threads...\n");
	
	Thread* t;
	
	//initialize Customers
	if(PRINT_DEBUG_MESSAGES) printf("Initializing customers\n");
	
	if(CUSTOMER_INIT_MODE == CONSTANT_NUMBER_OF_GROUPS)
	{
		for(int i = 0; i < NUM_GROUPS; i++)
		{
			customerInitLock -> Acquire();
			
			t = new Thread("TestCustomer");
			t->Fork(Customer, i);
			i++;
			
			//Allow the newly forked customer to initialize
			customerInitCondition -> Wait(customerInitLock);
			customerStartLock -> Acquire();
			customerStartLock -> Release();
		}
		
		NUM_CUSTOMERS = numCustomersInTheater;
	}
	else if(CUSTOMER_INIT_MODE == CONSTANT_NUMBER_OF_CUSTOMERS)
	{
		int i = 0;
		while(numCustomersInTheater < NUM_CUSTOMERS)
		{
			customerInitLock -> Acquire();
			
			t = new Thread("TestCustomer");
			t->Fork(Customer, i);
			i++;
			
			//Allow the newly forked customer to initialize
			customerInitCondition -> Wait(customerInitLock);
			customerStartLock -> Acquire();
			customerStartLock -> Release();
		}
		
		NUM_GROUPS = numGroupsInTheater;
	}
	
	//======== Preliminary Print Outputs ========
	
	if(PRINT_OUTPUT_MESSAGES)
	{
		printf("\n");
		printf("===========================================\n");
		printf("\n");
		printf("Initializing movie theater...done\n");
		printf("\n");
		printf("Number of Customers = %d\n", NUM_CUSTOMERS);
		printf("Number of Groups = %d\n", NUM_GROUPS);
		printf("Number of TicketClerks = %d\n", NUM_TICKET_CLERKS);
		printf("Number of ConcessionClerks = %d\n", NUM_CONCESSION_CLERKS);
		printf("Number of TicketTakers = %d\n", NUM_TICKET_TAKERS);
		printf("\n");
		printf("===========================================\n");
		printf("\n");
	}
	
	if(PRINT_DEBUG_MESSAGES)
	{
		printf("\n");
		printf("===========================================\n");
		printf("\n");
		printf("Initializing movie theater...done\n");
		printf("\n");
		printf("Number of Customers = %d\n", NUM_CUSTOMERS);
		printf("Number of Groups = %d\n", NUM_GROUPS);
		printf("Number of TicketClerks = %d\n", NUM_TICKET_CLERKS);
		printf("Number of ConcessionClerks = %d\n", NUM_CONCESSION_CLERKS);
		printf("Number of TicketTakers = %d\n", NUM_TICKET_TAKERS);
		printf("\n");
		printf("===========================================\n");
		printf("\n");
	}
	
	//initialize MovieTech
	t = new Thread("MovieTechnician");
	t->Fork(MovieTechnician, 0);
	
	//initialize TicketClerks
	for(int i = 0; i < NUM_TICKET_CLERKS; i++)
	{
		t = new Thread("TicketClerk");
		t->Fork(TicketClerk, i);
	}
	
	//initialize ConcessionClerks
	for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
	{
		t = new Thread("ConcessionClerk");
		t->Fork(ConcessionClerk, i);
	}
	
	//initialize TicketTakers
	for(int i = 0; i < NUM_TICKET_TAKERS; i++)
	{
		t = new Thread("TicketTaker");
		t->Fork(TicketTaker, i);
	}
	
	//initialize Manager
	if(PRINT_DEBUG_MESSAGES) printf("Initializing manager\n");
	t = new Thread("Manager");
	t->Fork(Manager, 0);
	
	//start all customers
	if(PRINT_DEBUG_MESSAGES) printf("Broadcasting to start %d customers\n", numCustomersInTheater);
	customerStartLock -> Acquire();
	customerStartCondition -> Broadcast(customerStartLock);
	customerStartLock -> Release();
}
	
//======== Customer Function ========
void Customer(int myIndex)
{
	//Create a random sized group of followers
	int myGroupSize = rand() % MAX_GROUP_SIZE + 1;
	
	//Synchronization so number of customers in theater is maintained
	numCustomersInTheaterLock -> Acquire();
	numCustomersInTheater += myGroupSize;
	while(numCustomersInTheater > NUM_CUSTOMERS && CUSTOMER_INIT_MODE == CONSTANT_NUMBER_OF_CUSTOMERS)
	{
		myGroupSize--;
		numCustomersInTheater--;
	}
	numCustomersInTheaterLock -> Release();
	numGroupsInTheaterLock -> Acquire();
	numGroupsInTheater++;
	numGroupsInTheaterLock -> Release();
	
	//Only one customer can be initialized at a time
	customerInitLock -> Acquire();
	customerStartLock -> Acquire();

	int myTicketClerk;
	int myConcessionClerk;
	int myTicketTaker;
	
	customerInitCondition -> Signal(customerInitLock);
	customerInitLock -> Release();
	customerStartCondition -> Wait(customerStartLock);
	
	customerStartLock -> Release();
	
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: entered the theater with group size of %d\n", myIndex, myGroupSize);
	for(int i = 0; i < myGroupSize; i++)
	{
		if(PRINT_OUTPUT_MESSAGES) printf("Customer %d in Group %d has entered the movie theater.\n", i, myIndex);
		currentThread -> Yield();
	}
	
	//================ Go To Ticket Clerk ================
	
	//special case for testing
	if(NUM_TICKET_CLERKS == 0)
	{
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: ERROR: No TicketClerks in theater!\n", myIndex);
		if(PRINT_OUTPUT_MESSAGES) printf("Group %d: No ConcessionClerks found, leaving theater...\n", myIndex);
		
		numCustomersInTheaterLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numCustomersInTheater\n", myIndex);
		numCustomersInTheater -= myGroupSize;
		numCustomersInTheaterLock -> Release();
		
		numGroupsInTheaterLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numGroupsInTheater\n", myIndex);
		numGroupsInTheater--;
		numGroupsInTheaterLock -> Release();
		
		overrideExitLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: leaving theater...\n", myIndex);
		overrideExitCondition -> Wait(overrideExitLock);
	}
	
	do
	{
		//Begin search for ticket clerks
		myTicketClerk = -1;
		
		//Lock down all lines from other customers/clerks for search
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: acquiring Lock for TicketClerk search\n", myIndex);
		tcLineManager -> Acquire();

		//See if any TicketClerk line is empty
		for(int i = 0;i < NUM_TICKET_CLERKS;i++)
		{
			if(tcState[i]== CLERK_AVAILABLE)
			{
				if(PRINT_TEST_CASE_MESSAGES)
					printf("TicketClerk %d has no line\n",i);
				//Join an empty line
				myTicketClerk = i;
				tcState[myTicketClerk] = CLERK_BUSY;
				if(PRINT_DEBUG_MESSAGES) printf("Customer %d: found available TicketClerk %d\n", myIndex, myTicketClerk);
				
				break;
			}
			else if(tcState[i] == CLERK_ON_BREAK)
			{
				if(PRINT_OUTPUT_MESSAGES) printf("Group %d sees TicketClerk %d is on break\n", myIndex, i);
			}
		}

		//If no lines were empty, join shortest line
		if(myTicketClerk  == -1){
			int shortestTCLineLength = tcLineLength[0];
			
			
			for(int i = 0;i < NUM_TICKET_CLERKS;i++)
			{
				if(PRINT_TEST_CASE_MESSAGES)
					printf("TicketClerk %d's line length is %d\n",i,tcLineLength[i]);
					
				if(tcState[i] == CLERK_BUSY && shortestTCLineLength >= tcLineLength[i])
				{
					myTicketClerk = i;
					shortestTCLineLength = tcLineLength[i];
				}
				else if(tcState[i] == CLERK_ON_BREAK)
				{
					if(PRINT_OUTPUT_MESSAGES) printf("Group %d sees TicketClerk %d is on break\n", myIndex, i);
				}
			}
			
			if(myTicketClerk == -1)
			{
				//If all ticket clerks are on break, wait in lobby
				tcLineManager -> Release();
				if(PRINT_DEBUG_MESSAGES) printf("Customer %d: ERROR: all TicketClerks on break\n", myIndex);
				if(PRINT_OUTPUT_MESSAGES) printf("Group %d: No TicketClerks found, leaving theater...\n", myIndex);
							
				numCustomersInTheaterLock -> Acquire();
				if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numCustomersInTheater\n", myIndex);
				numCustomersInTheater -= myGroupSize;
				numCustomersInTheaterLock -> Release();
				
				numGroupsInTheaterLock -> Acquire();
				if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numGroupsInTheater\n", myIndex);
				numGroupsInTheater--;
				numGroupsInTheaterLock -> Release();
				
				overrideExitLock -> Acquire();
				if(PRINT_DEBUG_MESSAGES) printf("Customer %d: leaving theater...\n", myIndex);
				overrideExitCondition -> Wait(overrideExitLock);
			}
			else
			{
				//Get in that line
				tcLineLength[myTicketClerk]++;
				
				//Wait to be signalled for ticket order
				if(PRINT_DEBUG_MESSAGES) printf("Customer %d: getting in line for TicketClerk %d\n", myIndex, myTicketClerk);
				tcLineCondition[myTicketClerk] -> Wait(tcLineManager);
			}
		}
	}
	while(myTicketClerk < 0 || tcState[myTicketClerk] == CLERK_ON_BREAK);
	
	//Release and allow other customers to search lines
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: releasing Lock for TicketClerk search\n", myIndex);
	tcLineManager -> Release();
		
	//After being signalled by TicketClerk to interact, lock down current clerk
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: TicketClerk %d is ready for interaction\n", myIndex, myTicketClerk);
	if(PRINT_OUTPUT_MESSAGES) printf("Group %d is walking up to TicketClerk %d to buy %d tickets.\n", myIndex, myTicketClerk, myGroupSize);
	tcInteractionLock[myTicketClerk] -> Acquire();

	//Give ticket order to clerk and signal TicketClerk to wake up
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: signalling TicketClerk %d for %d tickets\n", myIndex, myTicketClerk, myGroupSize);
	if(PRINT_OUTPUT_MESSAGES) printf("Group %d in TicketClerk line %d is paying %d for tickets.\n", myIndex, myTicketClerk, myGroupSize * TICKET_PRICE);
	
	numTicketsDesired[myTicketClerk] = myGroupSize;
	
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: waiting for response\n", myIndex);
	tcInteractionCondition[myTicketClerk] -> Signal(tcInteractionLock[myTicketClerk]);

	//Wait for TicketClerk to give tickets
	tcInteractionCondition[myTicketClerk] -> Wait(tcInteractionLock[myTicketClerk]);
	
	//After getting signalled by TicketClerk with completed ticket order
	tcInteractionLock[myTicketClerk] -> Acquire();
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: received %d tickets from TicketClerk %d\n", myIndex, numTicketsDesired[myTicketClerk], myTicketClerk);
	if(PRINT_OUTPUT_MESSAGES) printf("Group %d is leaving TicketClerk %d\n", myIndex, myTicketClerk);
	tcInteractionCondition[myTicketClerk] -> Signal(tcInteractionLock[myTicketClerk]);
	tcInteractionLock[myTicketClerk] -> Release();
	
	//================ Go To Concession Clerk ================
	
	//special case for testing
	if(NUM_CONCESSION_CLERKS == 0)
	{
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: ERROR: No ConcessionClerks in theater!\n", myIndex);
		if(PRINT_OUTPUT_MESSAGES) printf("Group %d: No ConcessionClerks found, leaving theater...\n", myIndex);
		
		numCustomersInTheaterLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numCustomersInTheater\n", myIndex);
		numCustomersInTheater -= myGroupSize;
		numCustomersInTheaterLock -> Release();
		
		numGroupsInTheaterLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numGroupsInTheater\n", myIndex);
		numGroupsInTheater--;
		numGroupsInTheaterLock -> Release();
		
		overrideExitLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: leaving theater...\n", myIndex);
		overrideExitCondition -> Wait(overrideExitLock);
	}
	
	//Calculate amount of popcorn and soda to order
	int numPopcornToOrder = 0;
	int numSodaToOrder = 0;
	
	for(int i = 0; i < myGroupSize; i++)
	{
		//Randomly select popcorn and soda
		int popcornWanted = 0;
		int sodaWanted = 0;
		
		int roll = rand() % 100 + 1;
		if(roll <= CUSTOMER_WANT_POPCORN_PROBABILITY)
		{
			popcornWanted = 1;
			numPopcornToOrder += popcornWanted;
		}
		
		roll = rand() % 100 + 1;
		if(roll <= CUSTOMER_WANT_SODA_PROBABILITY)
		{
			sodaWanted = 1;
			numSodaToOrder += sodaWanted;
		}
		
		currentThread -> Yield();
		
		if(PRINT_OUTPUT_MESSAGES) printf("Customer %d in group %d wants %d popcorn and %d soda.\n",
			i, myIndex, popcornWanted, sodaWanted);
	}
	
	//If any food is desired, approach ConcessionClerk lines
	if(numPopcornToOrder + numSodaToOrder > 0)
	{
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: %d popcorn and %d soda desired\n", myIndex, numPopcornToOrder, numSodaToOrder);
		
		do
		{
			//Begin search for ConcessionClerk
			myConcessionClerk = -1;
			
			//Lock down all lines from other customers/clerks for search
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: acquiring Lock for ConcessionClerk search\n", myIndex);
			ccLineManager -> Acquire();

			//See if any ConcessionClerk line is empty
			for(int i = 0;i < NUM_CONCESSION_CLERKS;i++)
			{
				if(PRINT_DEBUG_MESSAGES) printf("Customer %d: ConcessionClerk %d is in state: %d\n", myIndex, i, ccState[i]);
				
				if(ccState[i]== CLERK_AVAILABLE)
				{
					//Join an empty line
					myConcessionClerk = i;
					ccState[myConcessionClerk] = CLERK_BUSY;
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: found available ConcessionClerk %d\n", myIndex, myConcessionClerk);
					
					break;
				}
				else if(tcState[i] == CLERK_ON_BREAK)
				{
					if(PRINT_OUTPUT_MESSAGES) printf("Group %d sees ConcessionClerk %d is on break\n", myIndex, i);
				}
			}

			//If no lines were empty, join shortest line
			if(myConcessionClerk  == -1){
				int shortestCCLineLength = ccLineLength[0];
				
				for(int i = 0;i < NUM_CONCESSION_CLERKS;i++)
				{
					if(ccState[i] == CLERK_BUSY && shortestCCLineLength >= ccLineLength[i])
					{
						myConcessionClerk = i;
						shortestCCLineLength = ccLineLength[i];
					}
					else if(tcState[i] == CLERK_ON_BREAK)
					{
						if(PRINT_OUTPUT_MESSAGES) printf("Group %d sees ConcessionClerk %d is on break\n", myIndex, i);
					}
				}
				
				if(myConcessionClerk == -1)
				{					
					//If all ConcessionClerks are on break, wait in lobby
					ccLineManager -> Release();
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: ERROR: all ConcessionClerks on break!\n", myIndex);
					if(PRINT_OUTPUT_MESSAGES) printf("Group %d: No ConcessionClerks found, leaving theater...\n", myIndex);
					
					numCustomersInTheaterLock -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numCustomersInTheater\n", myIndex);
					numCustomersInTheater -= myGroupSize;
					numCustomersInTheaterLock -> Release();
					
					numGroupsInTheaterLock -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Decrementing numGroupsInTheater\n", myIndex);
					numGroupsInTheater--;
					numGroupsInTheaterLock -> Release();
					
					overrideExitLock -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: leaving theater...\n", myIndex);
					overrideExitCondition -> Wait(overrideExitLock);
				}
				else
				{
					//Get in that line
					ccLineLength[myConcessionClerk]++;
					
					//Wait to be signalled for food order
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: getting in line for ConcessionClerk %d\n", myIndex, myConcessionClerk);
					ccLineCondition[myConcessionClerk] -> Wait(ccLineManager);
				}
			}
		}
		while(myConcessionClerk < 0 || ccState[myConcessionClerk] == CLERK_ON_BREAK);
		
		//Release and allow other customers to search lines
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: releasing Lock for ConcessionClerk search\n", myIndex);
		ccLineManager -> Release();
			
		//After being signalled by ConcessionClerk to interact, lock down current clerk
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: ConcessionClerk %d is ready for interaction\n", myIndex, myConcessionClerk);
		if(PRINT_OUTPUT_MESSAGES) printf("Group %d is walking up to ConcessionClerk %d to buy %d popcorn and %d soda.\n", 
			myIndex, myConcessionClerk, numPopcornToOrder, numSodaToOrder);
		ccInteractionLock[myConcessionClerk] -> Acquire();

		//Give food order to clerk and signal ConcessionClerk to wake up
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: signalling ConcessionClerk %d for %d popcorn and %d soda\n", 
			myIndex, myConcessionClerk, numPopcornToOrder, numSodaToOrder);
		if(PRINT_OUTPUT_MESSAGES) printf("Group %d in ConcessionClerk line %d is paying %d for food.\n", 
			myIndex, myConcessionClerk, numPopcornToOrder * POPCORN_PRICE + numSodaToOrder * SODA_PRICE);
		
		numPopcornDesired[myConcessionClerk] = numPopcornToOrder;
		numSodaDesired[myConcessionClerk] = numSodaToOrder;
		
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: waiting for response\n", myIndex);
		ccInteractionCondition[myConcessionClerk] -> Signal(ccInteractionLock[myConcessionClerk]);

		//Wait for ConcessionClerk to give food
		ccInteractionCondition[myConcessionClerk] -> Wait(ccInteractionLock[myConcessionClerk]);
		
		//After getting signalled by ConcessionClerk with completed ticket order
		ccInteractionLock[myConcessionClerk] -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: received %d popcorn and %d soda from ConcessionClerk %d\n", 
			myIndex, numPopcornDesired[myConcessionClerk], numSodaDesired[myConcessionClerk], myConcessionClerk);
		if(PRINT_OUTPUT_MESSAGES) printf("Group %d is leaving ConcessionClerk %d\n", myIndex, myConcessionClerk);
		
		ccInteractionCondition[myConcessionClerk] -> Signal(ccInteractionLock[myConcessionClerk]);
		ccInteractionLock[myConcessionClerk] -> Release();
	}
	else
	{
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: no food desired, skipping ConcessionClerks\n", myIndex);
	}
	
	//=============== Go To TicketTaker ================
	
	//Flag controlling whether the TicketTaker has allowed the Customer in
	bool proceedToScreeningRoom = false;
	
	do
	{
		do
		{
			//Begin search for TicketTakers
			myTicketTaker = -1;
			
			//Lock down all lines from other customers/clerks for search
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: acquiring ttLineManager\n", myIndex);
			ttLineManager -> Acquire();

			//See if any TicketTaker line is empty
			for(int i = 0;i < NUM_TICKET_CLERKS;i++)
			{
				if(ttState[i]== CLERK_AVAILABLE && !ticketTakerFull[i] && !ttForcedToStop[i])
				{
					//Join an empty line
					myTicketTaker = i;
					ttState[myTicketTaker] = CLERK_BUSY;
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: found available TicketTaker %d\n", myIndex, myTicketTaker);
					
					break;
				}
				else if(tcState[i] == CLERK_ON_BREAK)
				{
					if(PRINT_OUTPUT_MESSAGES) printf("Group %d sees TicketTaker %d is on break\n", myIndex, i);
				}
			}

			//If no lines were empty, join shortest line
			if(myTicketTaker  == -1)
			{
				int shortestTTLineLength = ttLineLength[0];
				
				for(int i = 0;i < NUM_TICKET_CLERKS;i++)
				{
					if(ttState[i] == CLERK_BUSY && shortestTTLineLength >= ttLineLength[i] && !ticketTakerFull[i] && !ttForcedToStop[i])
					{
						myTicketTaker = i;
						shortestTTLineLength = ttLineLength[i];
					}
					else if(tcState[i] == CLERK_ON_BREAK)
					{
						if(PRINT_OUTPUT_MESSAGES) printf("Group %d sees TicketTaker %d is on break\n", myIndex, i);
					}
				}
				
				if(myTicketTaker == -1)
				{
					ttLineManager -> Release();
					
					//If all TicketTakers are on break, wait in lobby
					int myLobby = NUM_TICKET_TAKERS;					
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: all TicketTakers full or on break, going to lobby %d\n", myIndex, myLobby);
					
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: acquiring ttLobbyLock %d\n", myIndex, myLobby);
					ttLobbyLock[myLobby] -> Acquire();
					if(PRINT_OUTPUT_MESSAGES) printf("Group %d is in the lobby\n", myIndex);
					ttLobbyCondition[myLobby] -> Wait(ttLobbyLock[myLobby]);
					
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: signalled out of lobby, releasing ttLobbyLock %d\n", myIndex, myLobby);
					if(PRINT_OUTPUT_MESSAGES) printf("Group %d is leaving the the lobby\n", myIndex);
					ttLobbyLock[myLobby] -> Release();
				}
				else
				{
					//Get in that line
					ttLineLength[myTicketTaker]++;
					
					//Wait to be signalled for ticket order
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d: getting in line for TicketTaker %d\n", myIndex, myTicketTaker);
					
					ttLineCondition[myTicketTaker] -> Wait(ttLineManager);
				}
			} 
			//Release and allow other customers to search lines
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: releasing ttLineManager\n", myIndex);
			ttLineManager -> Release();
		}
		while(myTicketTaker < 0 || ttState[myTicketTaker] == CLERK_ON_BREAK || ticketTakerFull[myTicketTaker] || ttForcedToStop[myTicketTaker]);
		
		
			
		//After being signalled by TicketTaker to interact, lock down current clerk
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: TicketTaker %d is ready for interaction. Acquiring ttInteractionLock[%d]\n", myIndex, myTicketTaker, myTicketTaker);
		if(PRINT_OUTPUT_MESSAGES) printf("Group %d is walking up to TicketTaker %d to give %d tickets.\n", myIndex, myTicketTaker, myGroupSize);
		ttInteractionLock[myTicketTaker] -> Acquire();

		//Give ticket order to clerk and signal TicketTaker to wake up
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: signalling TicketTaker %d with %d tickets\n", myIndex, myTicketTaker, myGroupSize);
		
		numTicketsGiven[myTicketTaker] = myGroupSize;
		ttInteractionCondition[myTicketTaker] -> Signal(ttInteractionLock[myTicketTaker]);

		//Wait for TicketTaker to accept tickets or send to lobby
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: acquiring ttLobbyLock %d\n", myIndex, myTicketTaker);
		ttLobbyLock[myTicketTaker] -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: waiting for response on ttInteractionLock%d\n", myIndex, myTicketTaker);
		ttInteractionCondition[myTicketTaker] -> Wait(ttInteractionLock[myTicketTaker]);
		
		//After getting signalled by TicketTaker to go to the screening room or lobby	
		if(ticketTakerSaidToProceed[myTicketTaker])
		{
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: gave %d tickets to TicketTaker %d\n", myIndex, numTicketsGiven[myTicketTaker], myTicketTaker);
			if(PRINT_OUTPUT_MESSAGES) printf("Group %d is leaving TicketTaker %d\n", myIndex, myTicketTaker);
			proceedToScreeningRoom = true;
			ttLobbyLock[myTicketTaker] -> Release();
		}
		else
		{
			ttInteractionLock[myTicketTaker] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: TicketTaker %d full, waiting on ttLobbyLock %d\n", myIndex, myTicketTaker, myTicketTaker);
			if(PRINT_OUTPUT_MESSAGES) printf("Group %d sees TicketTaker %d is no longer taking tickets.  Going to lobby.\n", myIndex, myTicketTaker);
			ttLobbyCondition[myTicketTaker] -> Wait(ttLobbyLock[myTicketTaker]);
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Signalled out of lobby, releasing ttLobbyLock %d\n", myIndex, myTicketTaker);
			ttLobbyLock[myTicketTaker] -> Release();
		}
	}
	while(!proceedToScreeningRoom);
	
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: proceeding to screening room\n", myIndex);
	ttInteractionCondition[myTicketTaker] -> Signal(ttInteractionLock[myTicketTaker]);
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Releasing ttInteractionLock[%d]\n", myIndex, myTicketTaker);
	ttInteractionLock[myTicketTaker] -> Release();
	
	//================ Go To Screening Room ================
	
	screeningRoomLock -> Acquire();
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: figuring out screening room seating\n", myIndex);
	
	//Figure out how to seat followers
	int customerIndex = 0;
	int needSeats = myGroupSize;
	
	while(needSeats > 0)
	{
		if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Needs %d more seats\n", myIndex, needSeats);
	
		//Try to find the smallest row that fits all group members
		int smallestRowThatFits = getSmallestRowThatFits(needSeats);
		
		if(smallestRowThatFits >= 0)
		{
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Smallest row that fits: %d with %d free seats\n", 
				myIndex, smallestRowThatFits, getNumFreeSeats(smallestRowThatFits));
		}
		else
		{
			if(PRINT_DEBUG_MESSAGES) printf("Customer %d: No rows fit %d people, proceeding to split group\n",
				myIndex, needSeats);
		}
		
		//No row that fits all group members found, 
		if(smallestRowThatFits == -1)
		{
			//Find biggest row			
			int biggestRow = getBiggestRow();
			int biggestRowSize = getNumFreeSeats(biggestRow);
			
			int fillCol = 0;
			while(fillCol < SCREENING_ROOM_COLS)
			{
				if(screeningRoomSeat[biggestRow][fillCol] < 0)
				{				
					//Fill the seat
					screeningRoomSeat[biggestRow][fillCol] = myIndex;
					
					if(PRINT_DEBUG_MESSAGES) printf("Customer %d in Group %d has found the following seat: row %d and seat %d\n", 
						customerIndex, myIndex, biggestRow, fillCol);
					if(PRINT_OUTPUT_MESSAGES) printf("Customer %d in group %d is sitting in a theater room seat.\n",
						customerIndex, myIndex);
					
					//Decrement remaining seats, increment current customer
					needSeats--;
					customerIndex++;
				}
				
				fillCol++;
			}
			
			//Repeat loop with remaining people
		}
		else
		{
			//Smallest row that fits found, fill row and fill members in
			int fillCol = 0;
			while(needSeats > 0)
			{	
				if(screeningRoomSeat[smallestRowThatFits][fillCol] < 0)
				{
					//Fill the seat
					screeningRoomSeat[smallestRowThatFits][fillCol] = myIndex;
					
					if(PRINT_DEBUG_MESSAGES) printf("Group %d, Customer %d has found the following seat: row %d and seat %d\n", 
						myIndex, customerIndex, smallestRowThatFits, fillCol);
					
					//Decrement remaining seats, increment current customer
					needSeats--;
					customerIndex++;
				}
				
				fillCol++;
			}
		}
	}
	
	//Customer group successfully seated
	screeningRoomLock -> Release();
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: whole group successfully seated in theater\n", myIndex);
	
	//Wait for movie to start
	movieInProgressLock -> Acquire();
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: waiting for movie to start...\n", myIndex);
	movieInProgressCondition -> Wait(movieInProgressLock);
	
	//Signalled by MovieTechnician that movie is over	
	movieInProgressLock -> Release();
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: Signalled by MovieTechnician that movie is over\n", myIndex);
	
	//Now that movie is over, wait for group to get out of their seats
	screeningRoomLock -> Acquire();
	int leavingSeatIndex = 0;
	for(int c = 0; c < SCREENING_ROOM_COLS; c++)
	{
		for(int r = 0; r < SCREENING_ROOM_ROWS; r++)
		{
			if(screeningRoomSeat[r][c] == myIndex)
			{
				if(PRINT_OUTPUT_MESSAGES) printf("Customer %d in group %d is getting out of a theater room seat.\n", leavingSeatIndex, myIndex);
				if(PRINT_DEBUG_MESSAGES) printf("Group %d, Customer %d getting out of seat row %d, col %d\n", myIndex, leavingSeatIndex, r, c);
				
				screeningRoomSeat[r][c] = -1;
				leavingSeatIndex++;
				currentThread -> Yield();
			}
		}
	}
	screeningRoomLock -> Release();
	
	//================ Go To Bathroom ================
	
	//All follower Customers have exited their seats, ask if people want to go to the bathroom
	for(int i = 0; i < myGroupSize; i++)
	{
		//Randomly select bathroom
		int bathroomWanted = 0;
		
		int roll = rand() % 100 + 1;
		if(roll <= CUSTOMER_WANT_BATHROOM_PROBABILITY)
		{
			bathroomWanted = 1;
		}
		
		if(bathroomWanted == 1)
		{
			if(PRINT_OUTPUT_MESSAGES) printf("Customer %d in Group %d is going to the bathroom.\n", i, myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("Group %d, Customer %d wants to go to the bathroom.\n", myIndex, i);
			
			currentThread -> Yield();
			
			if(PRINT_OUTPUT_MESSAGES) printf("Customer %d in Group %d is leaving the bathroom.\n", i, myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("Group %d, Customer %d left the bathroom.\n", myIndex, i);
		}
		else
		{
			if(PRINT_DEBUG_MESSAGES) printf("Group %d, Customer %d does not want to go to the bathroom.\n", myIndex, i);
		}
	}
	
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: no more followers need to use the bathroom, proceeding to exit\n", myIndex);
	
	/*
	for(int i = 0; i < myGroupSize; i++)
	{
		followerCustomerInitLock -> Acquire();
		
		Thread* fc;
		fc = new Thread("FollowerCustomer");
		fc -> Fork(FollowerCustomer, i);
		
		followerCustomerInitCondition -> Wait();
		
		followerCustomerStartLock -> Acquire();
		followerCustomerStartLock -> Release();
	}
	
	followerCustomerStartLock -> Acquire();
	followerCustomerStartCondition -> Broadcast(followerCustomerStartLock);
	followerCustomerStartLock -> Release();
	*/
	
		
	//Customer exits theater and decrements count
	if(PRINT_DEBUG_MESSAGES) printf("Customer %d: leaving theater\n", myIndex);
	
	numCustomersInTheaterLock -> Acquire();
	numCustomersInTheater -= myGroupSize;
	numCustomersInTheaterLock -> Release();
	
	numGroupsInTheaterLock -> Acquire();
	numGroupsInTheater--;
	numGroupsInTheaterLock -> Release();
		
	for(int i = 0; i < myGroupSize; i++)
	{
		if(PRINT_OUTPUT_MESSAGES) printf("Customer %d in Group %d has exited the movie theater.\n", i, myIndex);
		currentThread -> Yield();
	}
}

//======== Ticket Clerk Function ========
void TicketClerk(int myIndex)
{
	if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: created\n", myIndex);
	tcStateLock[myIndex] -> Acquire();
	tcState[myIndex] == CLERK_AVAILABLE;
	
	while(true)
	{
		//Wait for Customer's ticket order
		tcInteractionWaitLabel:
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: waiting for next Customer\n", myIndex);
		tcInteractionCondition[myIndex] -> Wait(tcInteractionLock[myIndex]);
		
		if(tcState[myIndex] == CLERK_ON_BREAK)
		{
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: going on break...\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring tcBreakLock %d\n", myIndex, myIndex);
			tcBreakLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: signalling tcInteractionLock %d\n", myIndex, myIndex);
			tcInteractionCondition[myIndex] -> Signal(tcInteractionLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: releasing tcInteractionLock %d\n", myIndex, myIndex);
			tcInteractionLock[myIndex] -> Release();
			goto tcBreakLabel;
		}
		
		//After getting signalled by Customer with ticket order
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring tcInteractionLock %d\n", myIndex, myIndex);
		tcInteractionLock[myIndex] -> Acquire();
		
		tcState[myIndex] = CLERK_BUSY;
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: processing ticket order of size %d\n", myIndex, numTicketsDesired[myIndex]);
		if(PRINT_OUTPUT_MESSAGES) printf("TicketClerk %d has an order for %d and the cost is %d.\n", 
			myIndex, numTicketsDesired[myIndex], numTicketsDesired[myIndex] * TICKET_PRICE);
		
		//Process ticket order and add to total
		profitLock -> Acquire();
		totalTicketsSold[myIndex] += numTicketsDesired[myIndex];
		profitLock -> Release();
		
		//Signal Customer to complete transaction		
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: signalling Customer with completed order of size %d\n", myIndex, numTicketsDesired[myIndex]);
		tcInteractionCondition[myIndex] -> Signal(tcInteractionLock[myIndex]);
		
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: waiting for Customer to receive tickets\n", myIndex);
		tcInteractionCondition[myIndex] -> Wait(tcInteractionLock[myIndex]);
		
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: Customer received tickets succesfully\n", myIndex);
		
		//Release state for manager to edit
		tcStateLock[myIndex] -> Release();
		
		//Finished dealing with customer, perhaps go on break
		tcStateLock[myIndex] -> Acquire();
		if(tcState[myIndex] == CLERK_ON_BREAK)
		{
			if(PRINT_OUTPUT_MESSAGES) printf("TicketClerk %d is going on break.\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: signalling Manager that I am going on break\n", myIndex);
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring tcBreakStopLock %d\n", myIndex, myIndex);
			tcBreakStopLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring tcBreakLock %d\n", myIndex, myIndex);
			tcBreakLock[myIndex] -> Acquire();
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: signalling tcBreakStopLock %d\n", myIndex, myIndex);
			tcBreakStopCondition[myIndex] -> Signal(tcBreakStopLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: releasing tcBreakStopLock %d\n", myIndex, myIndex);
			tcBreakStopLock[myIndex] -> Release();
			
			tcBreakLabel:
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: releasing tcStateLock %d\n", myIndex, myIndex);
			tcStateLock[myIndex] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: waiting tcBreakLock %d\n", myIndex, myIndex);
			tcBreakCondition[myIndex] -> Wait(tcBreakLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring tcStateLock %d\n", myIndex, myIndex);
			tcStateLock[myIndex] -> Acquire();
			
			if(PRINT_OUTPUT_MESSAGES) printf("TicketClerk %d is coming off break.\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: returning from break\n", myIndex);
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring tcInteractionLock %d\n", myIndex, myIndex);
			tcInteractionLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: signalling tcBreakLock %d\n", myIndex, myIndex);
			tcBreakCondition[myIndex] -> Signal(tcBreakLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: releasing tcBreakLock %d\n", myIndex, myIndex);
			tcBreakLock[myIndex] -> Release();
			goto tcInteractionWaitLabel;
		}
		
		//Lock down lines before accepting next Customer
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring Lock for Customer search\n", myIndex);
		tcLineManager -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: acquiring tcInteractionLock %d\n", myIndex, myIndex);
		tcInteractionLock[myIndex] -> Acquire();
		
		//Check for customers in line
		if(tcLineLength[myIndex] > 0)
		{
			//I have a customer in line, set myself to busy and decrement line length
			if(PRINT_OUTPUT_MESSAGES) printf("TicketClerk %d has a line length %d and is signalling a customer.\n", myIndex, tcLineLength[myIndex]);
			
			tcState[myIndex] = CLERK_BUSY;
			tcLineLength[myIndex]--;
			
			//Wake up 1 customer
			tcLineCondition[myIndex] -> Signal(tcLineManager);
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: woke up next Customer\n", myIndex);
		}
		else
		{
			//No one in my line, set myself to available
			tcState[myIndex] = CLERK_AVAILABLE;
			if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: no Customers in line\n", myIndex);
			if(PRINT_OUTPUT_MESSAGES) printf("TicketClerk %d has no one in line.  I am available for a customer.\n", myIndex);
		}
		
		//Release and allow other Customers to search lines
		if(PRINT_DEBUG_MESSAGES) printf("TicketClerk %d: releasing Lock for Customer search\n", myIndex);
		tcLineManager -> Release();
	}
}

//======== Concession Clerk Function ========
void ConcessionClerk(int myIndex)
{
	if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: created\n", myIndex);
	ccStateLock[myIndex] -> Acquire();
	ccState[myIndex] == CLERK_AVAILABLE;
	
	while(true)
	{
		//Wait for Customer's food order
		ccInteractionWaitLabel:
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: waiting for next Customer\n", myIndex);
		ccInteractionCondition[myIndex] -> Wait(ccInteractionLock[myIndex]);
		
		if(ccState[myIndex] == CLERK_ON_BREAK)
		{
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: going on break...\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: acquiring ccBreakLock %d\n", myIndex, myIndex);
			ccBreakLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: signalling ccInteractionLock %d\n", myIndex, myIndex);
			ccInteractionCondition[myIndex] -> Signal(ccInteractionLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: releasing ccInteractionLock %d\n", myIndex, myIndex);
			ccInteractionLock[myIndex] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: waiting ccBreakLock %d\n", myIndex, myIndex);
			ccBreakCondition[myIndex] -> Wait(ccBreakLock[myIndex]);
			goto ccBreakLabel;
		}
		
		//After getting signalled by Customer with food order
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: acquiring ccInteractionLock %d\n", myIndex, myIndex);
		ccInteractionLock[myIndex] -> Acquire();
		
		ccState[myIndex] = CLERK_BUSY;
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: processing %d popcorn and %d soda\n", myIndex, numPopcornDesired[myIndex], numSodaDesired[myIndex]);
		if(PRINT_OUTPUT_MESSAGES) printf("ConcessionClerk %d has an order for %d popcorn and %d soda.  The cost is %d.\n", 
				myIndex, numPopcornDesired[myIndex], numSodaDesired[myIndex], numPopcornDesired[myIndex] * POPCORN_PRICE + numSodaDesired[myIndex] * SODA_PRICE);
		
		//Process food order and add to total
		profitLock -> Acquire();
		totalPopcornSold[myIndex] += numPopcornDesired[myIndex];
		totalSodaSold[myIndex] += numSodaDesired[myIndex];
		profitLock -> Release();
		
		//Signal Customer to complete transaction
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: signalling Customer with %d popcorn and %d soda\n", myIndex, numPopcornDesired[myIndex], numSodaDesired[myIndex]);
		ccInteractionCondition[myIndex] -> Signal(ccInteractionLock[myIndex]);
		
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: waiting for Customer to receive food\n", myIndex);
		ccInteractionCondition[myIndex] -> Wait(ccInteractionLock[myIndex]);
		
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: Customer received food succesfully\n", myIndex);
		
		//Release state for manager to edit
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: releasing ccStateLock %d\n", myIndex, myIndex);
		ccStateLock[myIndex] -> Release();
		
		//Finished dealing with customer, perhaps go on break
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: releasing ccStateLock %d\n", myIndex, myIndex);
		ccStateLock[myIndex] -> Acquire();
		if(ccState[myIndex] == CLERK_ON_BREAK)
		{
			if(PRINT_OUTPUT_MESSAGES) printf("ConcessionClerk %d is going on break.\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: signalling Manager that I am going on break\n", myIndex);
			
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: acquiring ccBreakStopLock %d\n", myIndex, myIndex);
			ccBreakStopLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: acquiring ccBreakLock %d\n", myIndex, myIndex);
			ccBreakLock[myIndex] -> Acquire();
			
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: signalling ccBreakStopLock %d\n", myIndex, myIndex);
			ccBreakStopCondition[myIndex] -> Signal(ccBreakStopLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: release ccBreakStopLock %d\n", myIndex, myIndex);
			ccBreakStopLock[myIndex] -> Release();
			
			ccBreakLabel:
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: releasing ccStateLock %d\n", myIndex, myIndex);
			ccStateLock[myIndex] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: waiting ccBreakLock %d\n", myIndex, myIndex);
			ccBreakCondition[myIndex] -> Wait(ccBreakLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: acquiring ccStateLock %d\n", myIndex, myIndex);
			ccStateLock[myIndex] -> Acquire();
			
			if(PRINT_OUTPUT_MESSAGES) printf("ConcessionClerk %d is coming off break.\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: returning from break\n", myIndex);
			
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: acquiring ccInteractionLock %d\n", myIndex, myIndex);
			ccInteractionLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: signalling ccBreakLock %d\n", myIndex, myIndex);
			ccBreakCondition[myIndex] -> Signal(ccBreakLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: releasing ccBreakLock %d\n", myIndex, myIndex);
			ccBreakLock[myIndex] -> Release();
			goto ccInteractionWaitLabel;
		}
		
		//Lock down lines before accepting next Customer
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: acquiring Lock for Customer search\n", myIndex);
		ccLineManager -> Acquire();
		ccInteractionLock[myIndex] -> Acquire();
		
		//Check for customers in line
		if(ccLineLength[myIndex] > 0)
		{
			//I have a customer in line, set myself to busy and decrement line length
			if(PRINT_OUTPUT_MESSAGES) printf("ConcessionClerk %d has a line length %d and is signalling a customer.\n", myIndex, tcLineLength[myIndex]);
			
			ccState[myIndex] = CLERK_BUSY;
			ccLineLength[myIndex]--;
			
			//Wake up 1 customer
			ccLineCondition[myIndex] -> Signal(ccLineManager);
			
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: woke up next Customer\n", myIndex);
		}
		else
		{
			//No one in my line, set myself to available
			ccState[myIndex] = CLERK_AVAILABLE;
			if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: no Customers in line\n", myIndex);
			if(PRINT_OUTPUT_MESSAGES) printf("ConcessionClerk %d has no one in line.  I am available for a customer.\n", myIndex);
		}
		
		//Release and allow other Customers to search lines
		if(PRINT_DEBUG_MESSAGES) printf("ConcessionClerk %d: releasing Lock for Customer search\n", myIndex);
		ccLineManager -> Release();
	}
}

//======== Ticket Taker Function ========
void TicketTaker(int myIndex)
{
	if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: created\n", myIndex);
	ttStateLock[myIndex] -> Acquire();
	ttState[myIndex] == CLERK_AVAILABLE;
	
	while(true)
	{
		if(ticketTakerFull[myIndex])
		{
			//Wait for next movie to start before resuming ticket taking
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Waiting for next movie before resuming ticket taking\n", myIndex);
			beginTakingTicketsLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: waiting on beginTakingTicketsLock\n", myIndex);
			ttWaitBeginTakingTickets: beginTakingTicketsCondition[myIndex] -> Wait(beginTakingTicketsLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalled out of beginTakingTicketsCondition\n", myIndex);
			
			//ticketTakerFullLock -> Acquire();
			ticketTakerFull[myIndex] = false;
			ttForcedToStop[myIndex] = false;
			ttState[myIndex] = CLERK_AVAILABLE;
			//ticketTakerFullLock -> Release();
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Acquiring ttInteractionLock[%d]\n", myIndex, myIndex);
			ttInteractionLock[myIndex] -> Acquire();
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalling beginTakingTicketsCondition\n", myIndex);
			beginTakingTicketsCondition[myIndex] -> Signal(beginTakingTicketsLock[myIndex]);
			beginTakingTicketsLock[myIndex] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Ready to resume ticket taking\n", myIndex);
			//ttInteractionCondition[myIndex] -> Wait(ttInteractionLock[myIndex]);
			//ttInteractionLock[myIndex] -> Release();
		}
		
		//Wait for the Customer's tickets
		ttInteractionWaitLabel:
		if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: waiting for next Customer\n", myIndex);
		ttInteractionCondition[myIndex] -> Wait(ttInteractionLock[myIndex]);
		
		if(ttState[myIndex] == CLERK_ON_BREAK)
		{
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: going on break...\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring ttBreakLock %d\n", myIndex, myIndex);
			ttBreakLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalling ttInteractionLock %d\n", myIndex, myIndex);
			ttInteractionCondition[myIndex] -> Signal(ttInteractionLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: releasing ttInteractionLock %d\n", myIndex, myIndex);
			ttInteractionLock[myIndex] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: waiting ttBreakLock %d\n", myIndex, myIndex);
			ttBreakCondition[myIndex] -> Wait(ttBreakLock[myIndex]);
			goto ttBreakLabel;
		}
		
		//At this point, check to see if you were woken up by a customer, or by a manager
		if(ttForcedToStop[myIndex])
		{
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Woken up by Manager for Stop\n", myIndex);
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring beginTakingTicketLock %d\n", myIndex, myIndex);
			beginTakingTicketsLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalling ttInteractionLock %d\n", myIndex, myIndex);
			ttInteractionCondition[myIndex] -> Signal(ttInteractionLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Releasing ttInteractionLock[%d]\n", myIndex, myIndex);
			ttInteractionLock[myIndex] -> Release();
			goto ttWaitBeginTakingTickets;
		}
		else
		
		{
			//After getting signalled by Customer with tickets		
			ttState[myIndex] = CLERK_BUSY;
			
			//Check if there is room in screening room
			ticketCountBoxLock -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: ticketCountBox currently has %d tickets\n", myIndex, ticketCountBox);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: processing %d incoming tickets from Customer\n", myIndex, numTicketsGiven[myIndex]);
			if(PRINT_OUTPUT_MESSAGES) printf("TicketClerk %d has received %d tickets.\n", myIndex, numTicketsGiven[myIndex]);
			
			ticketTakerFullLock -> Acquire();
			
			if((ticketTakerFull[myIndex]) || (ticketCountBox + numTicketsGiven[myIndex] > SCREENING_ROOM_CAPACITY))
			{
					
				//Lock the lines so that no Customer tries to join while TicketTaker gets full
				//ttLineManager -> Acquire();
				//If the Customer's group is too large, reject him from seating
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Not enough room for Customer!\n", myIndex);
				if(PRINT_OUTPUT_MESSAGES) printf("TicketTaker %d is not allowing the group into theater.  The number of taken tickets is %d and the group size is %d.\n",
					myIndex, ticketCountBox, numTicketsGiven[myIndex]);
					
				ticketTakerFull[myIndex] = true;
				ticketTakerSaidToProceed[myIndex] = false;
				
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: set myself to full, releasing ticketTakerFullLock\n", myIndex);
				if(PRINT_OUTPUT_MESSAGES) printf("Ticketaker %d has stopped taking tickets.\n", myIndex);
				
				//ttLineManager -> Release();
				ticketTakerFullLock -> Release();
				ticketCountBoxLock -> Release();
				
				//Signal current Customer with response
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Signalling current Customer to go to lobby\n", myIndex);
				ttInteractionCondition[myIndex] -> Signal(ttInteractionLock[myIndex]);
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Releasing ttInteractionLock[%d]\n", myIndex, myIndex);
				ttInteractionLock[myIndex] -> Release();
				//Wait for Customer signal
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Waiting for Customer to go to lobby\n", myIndex);
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Acquiring ttLobbyLock %d\n", myIndex, myIndex);
				ttLobbyLock[myIndex] -> Acquire();
				
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Customer went to lobby succesfully\n", myIndex);
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Releasing ttLobbyLock %d\n", myIndex, myIndex);
				ttLobbyLock[myIndex] -> Release();
			}
			else
			{
				ticketTakerFullLock -> Release();
				
				//If the Customer's group can fit, accept him for seating and add tickets to total
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: There is room for Customer, adding %d tickets to box.\n", myIndex, numTicketsGiven[myIndex]);
				if(PRINT_OUTPUT_MESSAGES) printf("TicketTaker %d is allowing the group into the theater.  The number of tickets taken is %d.\n",
					myIndex, numTicketsGiven[myIndex]);
					
				ticketTakerSaidToProceed[myIndex] = true;
				ticketCountBox += numTicketsGiven[myIndex];	
				
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: New ticket box total: %d\n", myIndex, ticketCountBox);
				ticketCountBoxLock -> Release();
				
				//Signal current Customer with response
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Signalling current Customer to go to screening room\n", myIndex);
				ttInteractionCondition[myIndex] -> Signal(ttInteractionLock[myIndex]);
				
				//Wait for Customer response 
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Waiting for Customer to go to screening room\n", myIndex);
				ttInteractionCondition[myIndex] -> Wait(ttInteractionLock[myIndex]);
				
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Customer went to screening room succesfully\n", myIndex);
			}
		}
		
		//Release state for manager to edit
		if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Releasing ttStateLock\n", myIndex);
		ttStateLock[myIndex] -> Release();
		
		//Finished dealing with Customer
		if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Acquiring ttStateLock\n", myIndex);
		ttStateLock[myIndex] -> Acquire();
		
		if(ttForcedToStop[myIndex])
		{
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Forced to Stop\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: stop acq\n", myIndex);
			ttStopLock -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: b acq\n", myIndex);
			beginTakingTicketsLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: stop sig\n", myIndex);
			ttStopCondition -> Signal(ttStopLock);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: stop wait\n", myIndex);
			ttStopCondition -> Wait(ttStopLock);
			ttStopLock -> Release();
			
			goto ttWaitBeginTakingTickets;
			/*
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: b wait\n", myIndex);
			beginTakingTicketsCondition[myIndex] -> Wait(beginTakingTicketsLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalled out of beginTakingTicketsCondition\n", myIndex);
				
			//ticketTakerFullLock -> Acquire();
			ticketTakerFull[myIndex] = false;
			//ticketTakerFullLock -> Release();
			
			ttInteractionLock[myIndex] -> Acquire();
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalling beginTakingTicketsCondition\n", myIndex);
			beginTakingTicketsCondition[myIndex] -> Signal(beginTakingTicketsLock[myIndex]);
			beginTakingTicketsLock[myIndex] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Ready to resume ticket taking\n", myIndex);
			//ttInteractionCondition[myIndex] -> Wait(ttInteractionLock[myIndex]);
			//ttInteractionLock[myIndex] -> Release();
				*/	
		
		}
		
		
		
		if(ttState[myIndex] == CLERK_ON_BREAK)
		{
			if(PRINT_OUTPUT_MESSAGES) printf("TicketTaker %d is going on break.\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalling Manager that I am going on break\n", myIndex);
						
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring ttBreakStopLock %d\n", myIndex, myIndex);
			ttBreakStopLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring ttBreakLock %d\n", myIndex, myIndex);
			ttBreakLock[myIndex] -> Acquire();
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalling ttBreakStopLock %d\n", myIndex, myIndex);
			ttBreakStopCondition[myIndex] -> Signal(ttBreakStopLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: releasing ttBreakStopLock %d\n", myIndex, myIndex);
			ttBreakStopLock[myIndex] -> Release();
			
			ttBreakLabel:
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring ttStateLock %d\n", myIndex, myIndex);
			ttStateLock[myIndex] -> Release();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: waiting ttBreakLock %d\n", myIndex, myIndex);
			ttBreakCondition[myIndex] -> Wait(ttBreakLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring ttStateLock %d\n", myIndex, myIndex);
			ttStateLock[myIndex] -> Acquire();
			
			if(PRINT_OUTPUT_MESSAGES) printf("TicketTaker %d is coming off break.\n", myIndex);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: returning from break\n", myIndex);
			
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring ttInteractionLock %d\n", myIndex, myIndex);
			ttInteractionLock[myIndex] -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: signalling ttBreakLock %d\n", myIndex, myIndex);
			ttBreakCondition[myIndex] -> Signal(ttBreakLock[myIndex]);
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: releasing ttBreakLock %d\n", myIndex, myIndex);
			ttBreakLock[myIndex] -> Release();
			goto ttInteractionWaitLabel;
		}
		
		//If we are full, exit loop and go to top
		if(!ticketTakerFull[myIndex])
		{
			//Lock down lines before accepting next Customer
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: acquiring ttLineManager\n", myIndex);
			ttLineManager -> Acquire();
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: Acquiring ttInteractionLock[%d]\n", myIndex, myIndex);
			ttInteractionLock[myIndex] -> Acquire();
			
			//Check for customers in line
			if(ttLineLength[myIndex] > 0)
			{
				if(PRINT_OUTPUT_MESSAGES) printf("TicketTaker %d has a line length %d and is signalling a customer.\n", myIndex, tcLineLength[myIndex]);
			
				//Customers are in line, set state to busy and decrement line length
				ttState[myIndex] = CLERK_BUSY;
				ttLineLength[myIndex]--;
				
				//Wake up next customer
				ttLineCondition[myIndex] -> Signal(ttLineManager);
				
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: woke up next Customer\n", myIndex);
			}
			else
			{
				//No Customers in line, set state to available
				ttState[myIndex] = CLERK_AVAILABLE;
				if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: no Customers in line\n", myIndex);
				if(PRINT_OUTPUT_MESSAGES) printf("TicketClerk %d has no one in line.  I am available for a customer.\n", myIndex);
			}
			
			//Release and allow other Customers to search lines
			if(PRINT_DEBUG_MESSAGES) printf("TicketTaker %d: releasing ttLineManager\n", myIndex);
			ttLineManager -> Release();
		}
	}
}

//======== Manager Function ========
void Manager(int myIndex)
{
	if(PRINT_DEBUG_MESSAGES) printf("Manager created\n");
	numCustomersInTheaterLock -> Acquire();
	
	int loops = 0;
	
	do
	{
		
		numCustomersInTheaterLock -> Release();
		for(int i = 0; i < 10; i++){
		currentThread -> Yield();
		}
		if(PRINT_DEBUG_MESSAGES) printf("Manager: Loop #%d\n", loops);
		loops++;
		if(PRINT_DEBUG_MESSAGES && MOVIE_STATE == ROOM_EMPTY) printf("Manager: Movie state is ROOM_EMPTY\n");
		if(PRINT_DEBUG_MESSAGES && MOVIE_STATE == ACCEPTING_TICKETS) printf("Manager: Movie state is ACCEPTING_TICKETS\n");
		if(PRINT_DEBUG_MESSAGES && MOVIE_STATE == CUSTOMER_CUTOFF) printf("Manager: Movie state is CUSTOMER_CUTOFF\n");
		if(PRINT_DEBUG_MESSAGES && MOVIE_STATE == IN_PROGRESS) printf("Manager: Movie state is IN_PROGRESS\n");
		if(PRINT_DEBUG_MESSAGES && MOVIE_STATE == ROOM_EMPTYING) printf("Manager: Movie state is ROOM_EMPTYING\n");
		/*
	
		
	
		STATES
	
		ROOM_EMPTY: movie has ended, screening room is empty (initial state, also set by movie tech). manager can randomly decide to start next movie.
		when he does, he activates the takers, announces to the lobby and changes the state to...

		ACCEPTING_TICKETS: customers are handing tickets to ticket takers. this goes on until all ticket takers are full. ticket takers can also be randomly
		set to full by the manager when he feels like it. whenever a taker is full, his line is disbanded. when manager detects that all ticket
		takers are full he changes the state to:

		CUSTOMER_CUTOFF: ticket takers are deactivated, customers are filling the seats. this goes on until the number in the ticket countbox matches the
		number of seated people in the theater. when this happens the movie tech changes state and yields for a while

		IN_PROGRESS: movie tech is yielding. when the yield ends, first thing he does is change the state to...

		ROOM_EMPTYING: movie tech busy loops waiting for the number of seated people to hit zero. when this occurs he changes the state back to BEGIN
	
	
	
		*/
	
		//if in ROOM_EMPTY state and loop multiple of XXXX
		//roll to see if you want to start taking customers. if so:
		//activate ticket takers. wait until they have all been successfully activated
		//broadcast to the lobby so customers bum-rush the ticket takers
		//set state to ACCEPTING_TICKETS, yield certain number of times (to prevent accepting state from not lasting long enough)
		movieStateLock -> Acquire();
		if((MOVIE_STATE == ROOM_EMPTY) && ((loops % MANAGER_DELAY_ACCEPTING) == 0))
		{
			if((rand() % 101) <= MANAGER_ROLL_ACCEPT)
			{
				if(PRINT_DEBUG_MESSAGES) printf("Manager has decided to start the movie process!\n");
				
				for(int i = 0; i < NUM_TICKET_TAKERS; i++)
				{
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Activating Ticket Taker %d \n", i);
					if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring beginTakingTickets\n");
					beginTakingTicketsLock[i] -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Signalling beginTakingTickets\n");
					beginTakingTicketsCondition[i] -> Signal(beginTakingTicketsLock[i]);
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Waiting beginTakingTickets\n");
					beginTakingTicketsCondition[i] -> Wait(beginTakingTicketsLock[i]);
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing beginTakingTicketsLock[%d]\n", i);
					beginTakingTicketsLock[i] -> Release();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttInteractionLock[%d]\n", i);
					ttInteractionLock[i] -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttInteractionLock[%d]\n", i);
					ttInteractionLock[i] -> Release();
				}
				/*
				for(int i = 0; i < NUM_TICKET_TAKERS; i++)
				{
					if(ttState[i] != CLERK_ON_BREAK && ticketTakerFull[i])
					{
						if(PRINT_DEBUG_MESSAGES) printf("Manager acquiring beginTakingTicketsLock\n");
						beginTakingTicketsLock -> Acquire();
						//Signal to begin taking tickets
						if(PRINT_DEBUG_MESSAGES) printf("Manager signaling beginTakingTicketsLock\n");
						beginTakingTicketsCondition -> Signal(beginTakingTicketsLock);
						//Wait for confirmation
						if(PRINT_DEBUG_MESSAGES) printf("Manager waiting beginTakingTicketsLock\n");
						beginTakingTicketsCondition -> Wait(beginTakingTicketsLock);
						beginTakingTicketsLock -> Release();
					}
				
				
				
				}
				*/
				
				/*beginTakingTicketsLock -> Acquire();			
				beginTakingTicketsCondition -> Broadcast(beginTakingTicketsLock);
				beginTakingTicketsLock -> Release();
			
				int readyTicketTakers;
				do
				{
					readyTicketTakers = 0;
					int i = 0;
					for(i; i < NUM_TICKET_TAKERS; i++)
					{
						ticketTakerFullLock -> Acquire();
						if(!ticketTakerFull[i])
						{
							readyTicketTakers++;
						}
						ticketTakerFullLock -> Release();
					}
					if(PRINT_DEBUG_MESSAGES) printf("Manager: %d out of %d Ticket Takers are ready to take tickets.\n", readyTicketTakers, NUM_TICKET_TAKERS);
				}
				while(readyTicketTakers < NUM_TICKET_TAKERS);
				*/
				if(PRINT_DEBUG_MESSAGES) printf("Manager: All Ticket Takers are ready to take tickets.\n");
				
				//Note: this for loop goes to NUM_TICKET_TAKERS + 1 to account for the extra lobby for Customers who found no TicketTakers
				for(int i = 0; i < NUM_TICKET_TAKERS + 1; i++)
				{
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttLobbyLock %d\n", i);
					ttLobbyLock[i] -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Broadcasting to ttLobbyLock %d\n", i);
					ttLobbyCondition[i] -> Broadcast(ttLobbyLock[i]);
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttLobbyLock %d\n", i);
					ttLobbyLock[i] -> Release();
				}
				
				MOVIE_STATE = ACCEPTING_TICKETS;
				loops = 0;
				
				for(int i = 0; i < MANAGER_YIELD_ACCEPTING; i++)
				{
					currentThread -> Yield();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Yield #%d\n", i);
				}
			
			}
			else
			{
				if(PRINT_DEBUG_MESSAGES) printf("Manager has decided to NOT start the movie process right now!\n");
			}
		}
		
		//if in ACCEPTING_TICKETS state (any loop multiple, but this is implicit)
		//iterate through fullness of ticket takers
		//if it's full, disband their line (do we need a local variable to track that we've already disbanded it to prevent doing it again?)
		//check if in loop multiple of XXXXX
		//if so, force them all to be full
		//(any loop) if there are no active ticket takers (full and break are inactive), tell movie tech to start movie. change state to CUSTOMER_CUTOFF (and reset the local array of booleans for line disbands)
		
		if(MOVIE_STATE == ACCEPTING_TICKETS)
		{
			
			//if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ticketTakerFullLock\n");
			//ticketTakerFullLock -> Acquire();
			
			/*
			for(int i = 0; i < NUM_TICKET_TAKERS; i++)
			{
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttStateLock[%d]\n", i);
			ttStateLock[i] -> Acquire();
			}
			*/
			
			int activeTicketTakers = 0;
			//maybe force ticket takers to be full
			//for all full ticket takers, disband their lines
			for(int i = 0; i < NUM_TICKET_TAKERS; i++)
			{
				if((loops % MANAGER_DELAY_CUTOFF == 0) && (ttState[i] != CLERK_ON_BREAK) && (!ticketTakerFull[i]))
				{
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Forcing TicketTaker %d to stop taking tickets\n", i);
					//force this active clerk to be full.
					
					ttLineManager -> Acquire();
					if(ttState[i] == CLERK_AVAILABLE)
					{
						ttForcedToStop[i] = true;
						if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttInteractionLock[%d]\n", i);
						ttInteractionLock[i] -> Acquire();
						ttInteractionCondition[i] -> Signal(ttInteractionLock[i]);
						ttInteractionCondition[i] -> Wait(ttInteractionLock[i]);
						if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttInteractionLock[%d]\n", i);
						ttInteractionLock[i] -> Release();
						beginTakingTicketsLock[i] -> Acquire();
						beginTakingTicketsLock[i] -> Release();
						ttLineManager -> Release();
					}
					else
					{
					ttLineManager -> Release();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttStateLock %d\n", i);
					ttStateLock[i] -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Setting TicketTaker %d's global stop boolean to true\n", i);
					ttForcedToStop[i] = true;
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttStopLock\n");
					ttStopLock -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttStateLock %d\n", i);
					ttStateLock[i] -> Release();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Waiting for ttStopCondition on ttStopLock\n");
					ttStopCondition -> Wait(ttStopLock);
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Signalling ttStopCondition on ttStopLock\n");
					ttStopCondition -> Signal(ttStopLock);
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttStopLock\n");
					ttStopLock -> Release();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring beginTakingTickstLock %d\n", i);
					beginTakingTicketsLock[i] -> Acquire();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing beginTakingTicketsLock %d\n", i);
					beginTakingTicketsLock[i] -> Release();
					if(PRINT_DEBUG_MESSAGES) printf("Manager: TicketTaker %d has been forced to be stop taking tickets\n", i);
					//at this point, the tickettaker has executed beginTakingTicketsCondition -> Wait(beginTakingTicketsLock)
					
					
					
					/*
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Forcing Ticket Taker %d to be FULL\n", i);
					ticketTakerFull[i] = true;*/
					}
				}
			
				if(ticketTakerFull[i] || ttForcedToStop[i])
				{
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Ticket Taker %d is FULL\n", i);
					//disband their line
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttLineManager\n");
					ttLineManager -> Acquire();
					ttLineCondition[i] -> Broadcast(ttLineManager);
					ttLineLength[i] = 0;
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttLineManager\n");
					ttLineManager -> Release();
				}
				else if(ttState[i] != CLERK_ON_BREAK) // not full, not on break == active
				{
					activeTicketTakers++;
				}
			}
			
			/*
			for(int i = 0; i < NUM_TICKET_TAKERS; i++)
			{
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttStateLock[%d]\n", i);
			ttStateLock[i] -> Release();
			}
			*/
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Active ticket takers: %d\n", activeTicketTakers);
			
			//if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ticketTakerFullLock\n");
			//ticketTakerFullLock -> Release();
			
			//if all ticket takers are full its time to go to next phase
			
			
			
			if(activeTicketTakers == 0)
			{
			//make sure all ticket takers are not dealing with customers
			//signal movie tech
				//if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ticketTakerFullLock\n");
				//ticketTakerFullLock -> Acquire();
				
				/*
				for(int i = 0; i < NUM_TICKET_TAKERS; i++)
				{
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring ttStateLock[%d]\n", i);
					ttStateLock[i] -> Acquire();
				}
				*/
				if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring movieTechLock\n");
				movieTechLock -> Acquire();
				MOVIE_STATE = CUSTOMER_CUTOFF;
				if(PRINT_DEBUG_MESSAGES) printf("Manager: Signalling MovieTechnician to start movie when all Customers are seated.\n");
				if(PRINT_OUTPUT_MESSAGES) printf("Manager is telling the MovieTechnnician to start the movie.\n");
				movieTechCondition -> Signal(movieTechLock);
				if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing movieTechLock\n");
				movieTechLock -> Release();
				
				/*
				for(int i = 0; i < NUM_TICKET_TAKERS; i++)
				{
					if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ttStateLock[%d]\n", i);
					ttStateLock[i] -> Release();
				}*/
				//if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ticketTakerFullLock\n");
				//ticketTakerFullLock -> Release();
			}
			
			//if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing ticketTakerFullLock\n");
			//ticketTakerFullLock -> Release();
		}
		
		
		movieStateLock -> Release();
		
		//if loop multiple of XXXX
		//process profits
		
		if((loops % MANAGER_DELAY_PROFITS) == 0)
		{
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Processing Profits\n");
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring profitLock\n");
			profitLock -> Acquire();
			
			int tcRevenue = 0;
			int concRevenue = 0;
			
			for(int i = 0; i < NUM_TICKET_CLERKS; i++)
			{
				if(PRINT_DEBUG_MESSAGES) printf("Manager: totalTicketsSold[%d] = %d\n", i, totalTicketsSold[i]);
				int nextTcRevenue = totalTicketsSold[i] * TICKET_PRICE;
				tcRevenue += nextTcRevenue;
				if(PRINT_DEBUG_MESSAGES) printf("Manager: tcRevenue = $%d\n", tcRevenue);
				
				if(PRINT_OUTPUT_MESSAGES) printf("Manager collected $%d from TicketClerk %d.\n", nextTcRevenue, i);
			}
			
			for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
			{
				int nextConcRevenue = 0;
				nextConcRevenue += totalPopcornSold[i] * POPCORN_PRICE;
				nextConcRevenue += totalSodaSold[i] * SODA_PRICE;
				concRevenue += nextConcRevenue;
				if(PRINT_DEBUG_MESSAGES) printf("Manager: concRevenue = $%d\n", concRevenue);
				
				if(PRINT_OUTPUT_MESSAGES) printf("Manager collected $%d from ConcessionClerk %d.\n", nextConcRevenue, i);
			}
			
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Ticket Clerk Revenue: $%d\n", tcRevenue);
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Concessions Revenue: $%d\n", concRevenue);
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Total Revenue $%d\n", tcRevenue + concRevenue);
			
			if(PRINT_OUTPUT_MESSAGES) printf("Manager total money made by theater = %d\n", tcRevenue + concRevenue);			
			
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing profitLock\n");
			profitLock -> Release();
		}
		
		/*
		          BREAK STUFF. ACQUIRE ALL STATE LOCKS
		if(PRINT_DEBUG_MESSAGES) printf("Manager: Acquiring all state locks for break processing\n");
		for(int i = 0; i < NUM_TICKET_CLERKS; i++)
		{
			tcStateLock[i] -> Acquire();
		}
		
		for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
		{
			ccStateLock[i] -> Acquire();
		}
		
		for(int i = 0; i < NUM_TICKET_TAKERS; i++)
		{
			ttStateLock[i] -> Acquire();
		}
		if(PRINT_DEBUG_MESSAGES) printf("Manager: Finished acquiring all state locks\n");
		*/
		
		
		
		//on any loop
		//process taking people off break
		if(ENABLE_BREAKS)
		{
			if(tcsOnBreak > 0)
			{
				if(PRINT_DEBUG_MESSAGES)
				 printf("Manager acquiring tcLineManager lock\n");
				tcLineManager -> Acquire();
				int longestLineLength = -1;
				int longestLineIndex = -1;
				
				
				//find longest line of a clerk that is not on break
				for(int i = 0; i < NUM_TICKET_CLERKS; i++)
				{	
					if((tcState[i] != CLERK_ON_BREAK) && (tcLineLength[i] > longestLineLength))
					{
						longestLineLength = tcLineLength[i];
						longestLineIndex = i;
					}
				}
				
				if(longestLineLength > MANAGER_LONGLINE)
				{
					//find someone to take off break
					//take them off break
					//disband longest line
							
					for(int i = 0; i < NUM_TICKET_CLERKS; i++)
					{
						if(tcState[i] == CLERK_ON_BREAK)
						{			
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager acquiring tcBreakLock%d\n",i);
							tcBreakLock[i] -> Acquire();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager signal tcBreakCondition%d\n",i);
							tcBreakCondition[i] -> Signal(tcBreakLock[i]);
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager waiting on tcBreakCondition%d\n",i);
							tcBreakCondition[i] -> Wait(tcBreakLock[i]);
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager signalled awake on tcBreakCondition%d and releasing\n",i);
							tcBreakLock[i] -> Release();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager acquiring tcInterationLock%d\n",i);
							tcInteractionLock[i] -> Acquire();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager releasing tcInteractionLock%d\n",i);
							tcInteractionLock[i] -> Release();
							tcState[i] = CLERK_AVAILABLE;
							tcsOnBreak--;						
							break;
						}
					}
						//disband longest line
						if(PRINT_DEBUG_MESSAGES)
								printf("Manager broadcasting tcLineCondition%d\n",longestLineIndex);
						tcLineCondition[longestLineIndex] -> Broadcast(tcLineManager);
						tcLineLength[longestLineIndex] = 0;
				}
				if(PRINT_DEBUG_MESSAGES)
					printf("Manager releasing tcLineManager lock\n");
				tcLineManager -> Release();
			}
			
			
			
			if(ccsOnBreak > 0)
			{
				if(PRINT_DEBUG_MESSAGES)
					printf("Manager acquiring ccLineManager lock\n");
				ccLineManager -> Acquire();
				int longestLineLength = -1;
				int longestLineIndex = -1;
				
				//find longest line of a clerk that is not on break
				for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
				{	
					if((ccState[i] != CLERK_ON_BREAK) && (ccLineLength[i] > longestLineLength))
					{
						longestLineLength = ccLineLength[i];
						longestLineIndex = i;
					}
				}
				
				if(longestLineLength > MANAGER_LONGLINE)
				{
					//find someone to take off break
					//take them off break
					//disband longest line
							
					for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
					{
						if(ccState[i] == CLERK_ON_BREAK)
						{			
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager acquiring ccBreakLock%d\n",i);
							ccBreakLock[i] -> Acquire();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager signalling ccBreakCondition%d\n",i);
							ccBreakCondition[i] -> Signal(ccBreakLock[i]);
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager waiting on ccBreakCondition%d\n",i);
							ccBreakCondition[i] -> Wait(ccBreakLock[i]);
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager signalled awake and realeasing ccBreakLock%d\n",i);
							ccBreakLock[i] -> Release();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager acquiring ccInterActionLock%d\n",i);
							ccInteractionLock[i] -> Acquire();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager releasing ccInteractionLock%d\n",i);
							ccInteractionLock[i] -> Release();
							ccState[i] = CLERK_AVAILABLE;
							ccsOnBreak--;						
							break;
						}
					}
						//disband longest line
						if(PRINT_DEBUG_MESSAGES)
								printf("Manager broadcasting ccLineCondition%d\n",longestLineIndex);
						ccLineCondition[longestLineIndex] -> Broadcast(ccLineManager);
						ccLineLength[longestLineIndex] = 0;
				}
				if(PRINT_DEBUG_MESSAGES)
								printf("Manager releasing tcLineManager\n");
				tcLineManager -> Release();
			}
			
			
			if(ttsOnBreak > 0)
			{
				if(PRINT_DEBUG_MESSAGES)
					printf("Manager acquiring ttLineManager\n");
				ttLineManager -> Acquire();
				int longestLineLength = -1;
				int longestLineIndex = -1;
				
				//find longest line of a clerk that is not on break
				for(int i = 0; i < NUM_TICKET_TAKERS; i++)
				{	
					if((ttState[i] != CLERK_ON_BREAK) && (ttLineLength[i] > longestLineLength))
					{
						longestLineLength = ttLineLength[i];
						longestLineIndex = i;
					}
				}
				
				if(longestLineLength > MANAGER_LONGLINE)
				{
					//find someone to take off break
					//take them off break
					//disband longest line
							
					for(int i = 0; i < NUM_TICKET_TAKERS; i++)
					{
						if(ttState[i] == CLERK_ON_BREAK)
						{	
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager acquiring ttBreakLock%d\n",i);
							ttBreakLock[i] -> Acquire();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager signalling ttBreakCondition%d\n",i);
							ttBreakCondition[i] -> Signal(ttBreakLock[i]);
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager waiting on ttBreakCondition%d\n",i);
							ttBreakCondition[i] -> Wait(ttBreakLock[i]);
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager signalled awake and releasing ttBreakLock%d\n",i);
							ttBreakLock[i] -> Release();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager acquiring ttInteractionLock%d\n",i);
							ttInteractionLock[i] -> Acquire();
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager releasing ttInteractionLock%d\n",i);
							ttInteractionLock[i] -> Release();
							ttState[i] = CLERK_AVAILABLE;
							ttsOnBreak--;						
							break;
						}
					}
						//disband longest line
						if(PRINT_DEBUG_MESSAGES)
								printf("Manager broadcasting ttLineCondition%d\n",longestLineIndex);
						ttLineCondition[longestLineIndex] -> Broadcast(ttLineManager);
						ttLineLength[longestLineIndex] = 0;
				}
				if(PRINT_DEBUG_MESSAGES)
								printf("Manager releasing ttLineManager\n");
				ttLineManager -> Release();
			}
			
			
			//on loop multiple of XXXX
			//process putting one person on break on break. remember to not put full ticket takers on break.
			//must disband line after putting someone on break
			
			
			if(loops % MANAGER_DELAY_BREAK == 0)
			{
				if(tcsOnBreak < NUM_TICKET_CLERKS - 1)
				{
					if(PRINT_DEBUG_MESSAGES)
						printf("Manager acquiring tcLineManager\n");
					tcLineManager -> Acquire();
					
					//check to see if anyone has no one in their line (force avail to break scenario)
					
					for(int i = 0; i < NUM_TICKET_CLERKS; i++)
					{
						printf("Manager: TicketClerk %d has state %d\n", i, tcState[i]);
						if(tcState[i] == CLERK_AVAILABLE)
						{
							if(rand() % 101 <= MANAGER_ROLL_ONBREAK)
							{
								tcState[i] = CLERK_ON_BREAK;
								tcsOnBreak++;
								if(PRINT_DEBUG_MESSAGES)
									printf("Manager acquiring tcInteractionLock%d\n",i);
								tcInteractionLock[i] -> Acquire();
								if(PRINT_DEBUG_MESSAGES)
									printf("Manager signalling tcInteractionConditon%d\n",i);
								tcInteractionCondition[i] -> Signal(tcInteractionLock[i]);
								if(PRINT_DEBUG_MESSAGES)
									printf("Manager waiting tcInteractionCondition%d\n",i);
								tcInteractionCondition[i] -> Wait(tcInteractionLock[i]);
								if(PRINT_DEBUG_MESSAGES)
									printf("Manager releasing tcInteractionLock%d\n",i);
								tcInteractionLock[i] -> Release();
								if(PRINT_DEBUG_MESSAGES)
									printf("Manager acquiring tcInteractionLock%d\n",i);
								tcBreakLock[i] -> Acquire();
								if(PRINT_DEBUG_MESSAGES)
									printf("Manager releasing tcInteractionLock%d\n",i);
								tcBreakLock[i] -> Release();
								
								//disband line
								if(PRINT_DEBUG_MESSAGES)
									printf("Manager broadcasting tcLineCondition%d\n",i);
								tcLineCondition[i] -> Broadcast(tcLineManager);
								tcLineLength[i] = 0;
							}
							
							if(PRINT_DEBUG_MESSAGES)
								printf("Manager releasing tcLineManager\n");
							tcLineManager -> Release();
							goto managerEnd;
						}
					}
					
					//loop through ACTIVE line lengths and find the first person with less than MANAGER_SHORTLINE people
					int shortLineIndex = -1;
					for(int j = 0; j < NUM_TICKET_CLERKS; j++)
					{
						if((tcState[j] != CLERK_ON_BREAK)&&(tcLineLength[j] < MANAGER_SHORTLINE))
						{
							shortLineIndex = j;
							break;
						}
					}
					
					if(PRINT_DEBUG_MESSAGES)
						printf("Manager releasing tcLineManager\n");
					tcLineManager -> Release();
						
					if((shortLineIndex != -1)  && (rand() % 101 <= MANAGER_ROLL_ONBREAK))
					{
						int k = shortLineIndex;
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager acquiring tcStateLock%d\n",k);
						tcStateLock[k] -> Acquire();
						tcState[k] = CLERK_ON_BREAK;
						tcsOnBreak++;
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager acquiring tcBreakStopLock%d\n",k);
						tcBreakStopLock[k] -> Acquire();
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager releasing tcStateLock%d\n",k);
						tcStateLock[k] -> Release();
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager waiting on tcBreakStopCondition%d\n",k);
						tcBreakStopCondition[k] -> Wait(tcBreakStopLock[k]);
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager releasing tcBreakStopLock%d\n",k);
						tcBreakStopLock[k] -> Release();
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager acquiring tcBreakLock%d\n",k);
						tcBreakLock[k] -> Acquire();
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager releasing tcBreakLock%d\n",k);
						tcBreakLock[k] -> Release();
						
						if(PRINT_DEBUG_MESSAGES)
							printf("Manager broadcasting tcLineCondtion%d\n",k);
						tcLineCondition[k] -> Broadcast(tcLineManager);
						tcLineLength[k] = 0;
						
						goto managerEnd;
						
					}
					
					
					if(PRINT_DEBUG_MESSAGES)
							printf("Manager releasing tcLineManager\n");
						tcLineManager -> Release();
				}
			
				
				if(ccsOnBreak < NUM_CONCESSION_CLERKS - 1)
				{
				
					if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ccLineManager\n");
					ccLineManager -> Acquire();
					
					//check to see if anyone has no one in their line (force avail to break scenario)
					
					for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
					{
						if(ccState[i] == CLERK_AVAILABLE )
						{
							if(rand() % 101 <= MANAGER_ROLL_ONBREAK)
							{
								ccState[i] = CLERK_ON_BREAK;
								ccsOnBreak++;
								if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ccInteractionLock %d\n", i);
								ccInteractionLock[i] -> Acquire();
								if(PRINT_DEBUG_MESSAGES) printf("Manager: signalling ccInteractionLock %d\n", i);
								ccInteractionCondition[i] -> Signal(ccInteractionLock[i]);
								if(PRINT_DEBUG_MESSAGES) printf("Manager: waiting ccInteractionLock %d\n", i);
								ccInteractionCondition[i] -> Wait(ccInteractionLock[i]);
								if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ccInteractionLock %d\n", i);
								ccInteractionLock[i] -> Release();
								if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ccBreakLock %d\n", i);
								ccBreakLock[i] -> Acquire();
								if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ccBreakLock %d\n", i);
								ccBreakLock[i] -> Release();
								
								//disband line
								if(PRINT_DEBUG_MESSAGES) printf("Manager: broadcasting ccLineCondition %d\n", i);
								ccLineCondition[i] -> Broadcast(ccLineManager);
								ccLineLength[i] = 0;
							}
							
							if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ccLineManager\n");
							ccLineManager -> Release();
							goto managerEnd;
						}
					}
						
					//loop through ACTIVE line lengths and find the first person with less than MANAGER_SHORTLINE people
					int shortLineIndex = -1;
					for(int j = 0; j < NUM_CONCESSION_CLERKS; j++)
					{
						if((ccState[j] != CLERK_ON_BREAK)&&(ccLineLength[j] < MANAGER_SHORTLINE))
						{
							shortLineIndex = j;
							break;
						}
					}
					if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ccLineManager\n");
					ccLineManager -> Release();
					if((shortLineIndex != -1)  && (rand() % 101 <= MANAGER_ROLL_ONBREAK))
					{
						int k = shortLineIndex;
						if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ccStateLock %d\n", k);
						ccStateLock[k] -> Acquire();
						ccState[k] = CLERK_ON_BREAK;
						ccsOnBreak++;
						if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ccBreakStoplock %d\n", k);
						ccBreakStopLock[k] -> Acquire();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ccStateLock %d\n", k);
						ccStateLock[k] -> Release();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: waiting ccBreakStopLock %d\n", k);
						ccBreakStopCondition[k] -> Wait(ccBreakStopLock[k]);
						if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ccBreakStopLock %d\n", k);
						ccBreakStopLock[k] -> Release();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ccBreakLock %d\n", k);
						ccBreakLock[k] -> Acquire();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ccBreakLock %d\n", k);
						ccBreakLock[k] -> Release();
						
						if(PRINT_DEBUG_MESSAGES) printf("Manager: broadcasting ccLineManager %d\n", k);
						ccLineCondition[k] -> Broadcast(ccLineManager);
						ccLineLength[k] = 0;
						
						goto managerEnd;
					}
					
					ccLineManager -> Release();
				}
				
				
				//full or forced to stop ticket takers cannot go on break
				//cannot put last active ticket taker on break
				//first count active ticket takers (not on break, not full and not forced to stop)
				
				int activeTicketTakers = 0;
				ttLineManager -> Acquire();
				for(int i = 0; i < NUM_TICKET_TAKERS; i++)
				{
					if(ttState[i] == CLERK_AVAILABLE)
					{
						if(!ttForcedToStop[i] && !ticketTakerFull[i])
						{
						activeTicketTakers++;
						}
					}
					else
					{
						ttStateLock[i] -> Acquire();
						if(ttState[i] != CLERK_ON_BREAK && !ttForcedToStop[i] && !ticketTakerFull[i])
						{
						activeTicketTakers++;
						}
					}
				}
				
				if(activeTicketTakers > 1)
				{
					//ttLineManager -> Acquire();
					
					//check to see if anyone has no one in their line (force avail to break scenario)
					
					for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
					{
						if(ttState[i] == CLERK_AVAILABLE && !ticketTakerFull[i] && !ttForcedToStop[i])
						{
							if(rand() % 101 <= MANAGER_ROLL_ONBREAK)
							{
								ttState[i] = CLERK_ON_BREAK;
								ttsOnBreak++;
								if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ttInteractionLock %d\n", i);
								ttInteractionLock[i] -> Acquire();
								if(PRINT_DEBUG_MESSAGES) printf("Manager: signalling ttInteractionLock %d\n", i);
								ttInteractionCondition[i] -> Signal(ttInteractionLock[i]);
								if(PRINT_DEBUG_MESSAGES) printf("Manager: waiting ttInteractionLock %d\n", i);
								ttInteractionCondition[i] -> Wait(ttInteractionLock[i]);
								if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttInteractionLock %d\n", i);
								ttInteractionLock[i] -> Release();
								if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ttBreakLock %d\n", i);
								ttBreakLock[i] -> Acquire();
								if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttBreakLock %d\n", i);
								ttBreakLock[i] -> Release();
								
								//disband line
								if(PRINT_DEBUG_MESSAGES) printf("Manager: broadcasting ttLineManager\n");
								ttLineCondition[i] -> Broadcast(ttLineManager);
								ttLineLength[i] = 0;
							}
								
							//release stuff acquired earlier
							//ttStateLock[i] -> Release(); //never owned this lock since [i] was available
							for(int j = 0; j < NUM_TICKET_TAKERS; j++)
							{
								if(ttState[j] != CLERK_AVAILABLE)
								{
									ttStateLock[j] -> Release();
								}
							}
							
							if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttLineManager\n");
							ttLineManager -> Release();
							goto managerEnd;
						}
					}
						
					//loop through ACTIVE line lengths and find the first person with less than MANAGER_SHORTLINE people
					int shortLineIndex = -1;
					for(int j = 0; j < NUM_TICKET_TAKERS; j++)
					{
						if((ttState[j] != CLERK_ON_BREAK)&&(ttLineLength[j] < MANAGER_SHORTLINE)&& !ticketTakerFull[j] && !ttForcedToStop[j])
						{
							shortLineIndex = j;
							break;
						}
					}
						
					if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttLineManager\n");
					ttLineManager -> Release();
					
					if((shortLineIndex != -1)  && (rand() % 101 <= MANAGER_ROLL_ONBREAK) && !ticketTakerFull[shortLineIndex] && !ttForcedToStop[shortLineIndex])
					{
						int k = shortLineIndex;
						if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ttStateLock %d\n", k);
						ttStateLock[k] -> Acquire();
						ttState[k] = CLERK_ON_BREAK;
						ttsOnBreak++;
						if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ttBreakStopLock %d\n", k);
						ttBreakStopLock[k] -> Acquire();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttStateLock %d\n", k);
						ttStateLock[k] -> Release();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: waiting ttBreakStopLock %d\n", k);
						ttBreakStopCondition[k] -> Wait(ttBreakStopLock[k]);
						if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttBreakStopLock %d\n", k);
						ttBreakStopLock[k] -> Release();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: acquiring ttBreakLock %d\n", k);
						ttBreakLock[k] -> Acquire();
						if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttBreakLock %d\n", k);
						ttBreakLock[k] -> Release();
						
						if(PRINT_DEBUG_MESSAGES) printf("Manager: broadcasting ttLineManager\n");
						ttLineCondition[k] -> Broadcast(ttLineManager);
						ttLineLength[k] = 0;
						
						if(PRINT_DEBUG_MESSAGES) printf("Manager: releasing ttStateLock %d\n", k);
						ttStateLock[k] -> Release();
						for(int j = 0; j < NUM_TICKET_TAKERS; j++)
						{
							if(ttState[j] != CLERK_AVAILABLE)
							{
								ttStateLock[j] -> Release();
							}
						}
						
						goto managerEnd;
					}
					ttLineManager -> Release();
				}		
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			}
		
		
		
		
		
		
		
		
		
		
		
			/*
			if(PRINT_DEBUG_MESSAGES) printf("Manager: Releasing all state locks\n");
			for(int i = 0; i < NUM_TICKET_CLERKS; i++)
			{
				tcStateLock[i] -> Release();
			}
			
			for(int i = 0; i < NUM_CONCESSION_CLERKS; i++)
			{
				ccStateLock[i] -> Release();
			}
			
			for(int i = 0; i < NUM_TICKET_TAKERS; i++)
			{
				ttStateLock[i] -> Release();
			}
			*/
		
		
	
	
		}
	
	
	
		managerEnd:
		numCustomersInTheaterLock -> Acquire();
	}
	while(numCustomersInTheater > 0);
	numCustomersInTheaterLock -> Release();
	
	if(PRINT_DEBUG_MESSAGES) printf("No more customers in theater. Manager exiting.\n");
}

//======== Movie Technician Function ========
void MovieTechnician(int myIndex)
{
	if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician: created\n");
	
	while(true){
	
		//Wait for Manager to acknowledge movie is sold out
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician: acquiring movieTechLock\n");
		movieTechLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician: waiting for Manager to signal\n");
		movieTechCondition -> Wait(movieTechLock);
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician: signalled out of movieTechLock\n");
		movieTechLock -> Release();
		
		if(PRINT_DEBUG_MESSAGES)
			printf("MovieTechnician waiting for theater to fill\n");
			
		int ticketCount;
		int theaterCount;	
			
		// Wait for everyone to be seated in the theater
		do{		
			currentThread -> Yield();
			//Check current ticket count
			ticketCountBoxLock -> Acquire();			
			ticketCount = ticketCountBox;		
			ticketCountBoxLock -> Release();
			
			//Check number of customers seated in the screening room
			screeningRoomLock -> Acquire();
			theaterCount = getNumTakenSeats();
			screeningRoomLock -> Release();
			
			if(PRINT_DEBUG_MESSAGES)
				printf("MovieTechnician: ticketCount = %d, theaterCount = %d\n", ticketCount, theaterCount);
		
		}while(ticketCount > theaterCount);

		if(PRINT_DEBUG_MESSAGES)
			printf("MovieTechnician changing movie status to in progress\n");
		//Change the movie status to in progress
		movieStateLock -> Acquire();
		MOVIE_STATE = IN_PROGRESS;
		movieNumber++;
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician: Starting movie %d with %d customers in theater\n", movieNumber, theaterCount);
		movieStateLock -> Release();
		
		ticketCountBoxLock -> Acquire();			
		ticketCountBox = 0;		
		ticketCountBoxLock -> Release();
		
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician yeilding\n");
		if(PRINT_OUTPUT_MESSAGES) printf("The MovieTechnician has started the movie.\n");
			
		for(int i = 0;i < ((rand() % 101) + 200);i++){
			currentThread -> Yield();
		}
		
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician: Finished movie %d with %d customers in theater\n", movieNumber, theaterCount);
		if(PRINT_OUTPUT_MESSAGES) printf("The MovieTechnician has ended the movie.\n");
		
		//Change the movie status to in progress
		movieStateLock -> Acquire();
		MOVIE_STATE = ROOM_EMPTYING;
		movieStateLock -> Release();
		
		if(PRINT_DEBUG_MESSAGES)
			printf("MovieTechnician telling customers to leave\n");
		movieInProgressLock -> Acquire();
		movieInProgressCondition -> Broadcast(movieInProgressLock);
		movieInProgressLock -> Release();
		
		if(PRINT_OUTPUT_MESSAGES) printf("The MovieTechnician has told all customers to leave the theater room.\n");
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician waiting for screening room to empty\n");
		do{
			currentThread -> Yield();
			//Check number of customers seated in the screening room
			screeningRoomLock -> Acquire();
			theaterCount = getNumTakenSeats();
			screeningRoomLock -> Release();
			
		}while(theaterCount > 0);
		
		//Change the movie status to in progress
		movieStateLock -> Acquire();
		if(PRINT_DEBUG_MESSAGES) printf("MovieTechnician setting MOVIE_STATE to ROOM_EMPTY\n");
		MOVIE_STATE = ROOM_EMPTY;
		movieStateLock -> Release();
	}
}

#endif //CHANGED














